home *** CD-ROM | disk | FTP | other *** search
- /*
- * @package autofillForms
- * @author Sebastian Tschan
- * @copyright (c) Sebastian Tschan
- * @license GNU General Public License
- * @link https://blueimp.net/mozilla/
- */
-
- var autofillForms = {
-
- // The selected profile index:
- profileIndex: null,
- // The selected global profile index:
- globalProfileIndex: null,
- // The selected form fields context menu profile index
- formFieldsContextMenuProfileIndex: null,
- // The list of profile labels:
- profileLabels: null,
- // The list of profile site rules:
- profileSiteRules: null,
- // The list of form field rules:
- fieldRules: null,
- // The tree representing the field rules list:
- tree: null,
- // The tree view:
- treeView: null,
- // The tree view frontend:
- treeBox: null,
- // Holds the selection object for the treeview:
- selection: null,
- // Remembers the last selected index of the treeview:
- lastSelectedIndex: null,
- // Determines if sort is to be ascending or descending:
- ascending: null,
- // The profiles listBox:
- profilesTree: null,
- // The profiles tree view:
- profilesTreeView: null,
- // The profiles tree view frontend:
- profilesTreeBox: null,
- // Holds the selection object for the profiles treeview:
- profilesSelection: null,
- // The profiles sort order:
- profilesAscending: null,
- // Autofill forms preferences branch:
- autofillFormsPrefs: null,
- // Object containing the shortcuts information (modifiers, key or keycode):
- shortcut: null,
- // Object containing the mouse button shortcuts information:
- mouseButton: null,
- // Helper var to do the opposite of the current setting:
- invertedSetting: null,
- // Array containing the rule element types ("begins with", "contains", ...):
- ruleElementTypes: null,
- // Containes the reference to the current rule field:
- currentRuleField: null,
- // Defines the index selected for the last alternative fieldRules selection:
- fieldRuleAlternativesIndex: null,
- // Stores the length of the last created list of alternative fieldRules:
- fieldRuleAlternativesLength: null,
- // Hash to store lists of alternatives (used for radio input fields):
- fieldRuleAlternativesHash: null,
- // Cache to reuse/clone fieldRuleAlternatives on the same form fill run:
- fieldRuleAlternativesCache: null,
- // Array of dynamic tags:
- dynamicTags: null,
- // Array of dynamic tag codes, associated to the dynamic tags:
- dynamicTagCodes: null,
- // Determines if a textbox is focused on the rule editor:
- ruleEditorTextBoxFocused: null,
- // Determines if a textbox is focused on the tag editor:
- tagEditorTextBoxFocused: null,
- // References the last matched form element (used to set the focus):
- lastFormElementMatch: null,
- // References the current window when filling out forms:
- currentWindow: null,
- // Holds the index of the current form when filling out forms:
- currentFormIndex:null,
- // Holds the index of the current form element when filling out forms:
- currentElementIndex: null,
- // References the target form field on which the context menu has been invoked:
- targetFormField: null,
- // Event listener for the content area context menu:
- contentAreaContextMenuEventListener: null,
- // Holds the the tooltip grid which displays commands and their mouse buttons and keyboard shortcuts:
- tooltipGrid: null,
- // Holds the current profile tooltip label:
- tooltipCurrentProfile: null,
-
- initialize: function() {
- // Save the reference to the Autofill Forms preferences branch:
- this.autofillFormsPrefs = this.getPrefManager().getBranch('extensions.autofillForms@blueimp.net.');
-
- // Add a preferences observer to the autofillForms preferences branch:
- this.autofillFormsPrefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
- this.autofillFormsPrefs.addObserver('', this, false);
-
- // Implement the event listener for the content area context menu:
- this.contentAreaContextMenuEventListener = function(event) {
- autofillForms.initContentAreaContextMenu(event);
- }
-
- // Initialize the preferences settings:
- this.initializePrefs();
- },
-
- initContentAreaContextMenu: function(event) {
- var cm0 = document.getElementById('autofillFormsContextMenuItem');
- var cm1 = document.getElementById('autofillFormsContextMenu');
- var cm2 = document.getElementById('autofillFormsManualFillContextMenu');
- var cm3 = document.getElementById('autofillFormsAddRuleContextMenuItem');
- var cm4 = document.getElementById('autofillFormsAddFormAsProfileContextMenuItem');
- var cm5 = document.getElementById('autofillFormsContextMenuSeparator1');
- var cm6 = document.getElementById('autofillFormsContextMenuSeparator2');
- var cm7 = document.getElementById('autofillFormsDisplayFormDetailsContextMenuItem');
- if(cm0 && gContextMenu) {
- if(gContextMenu.target && this.isValidFormField(gContextMenu.target)) {
- cm0.hidden = true;
- cm1.hidden = true;
- if(this.autofillFormsPrefs.getBoolPref('hideFormFieldsContextMenu')) {
- cm2.hidden = true;
- cm3.hidden = true;
- cm4.hidden = true;
- cm5.hidden = true;
- cm6.hidden = true;
- cm7.hidden = true;
- this.targetFormField = null;
- } else {
- cm2.hidden = false;
- cm3.hidden = false;
- cm4.hidden = false;
- // Show menuseparators if not already separated:
- if(this.isPreviousNodeSeparated(cm5)) {
- cm5.hidden = true;
- } else {
- cm5.hidden = false;
- }
- if(this.isNextNodeSeparated(cm6)) {
- cm6.hidden = true;
- } else {
- cm6.hidden = false;
- }
- this.targetFormField = gContextMenu.target;
- }
- return;
- }
-
- if(this.autofillFormsPrefs.getBoolPref('hideContextMenuItem')
- || gContextMenu.isContentSelected
- || gContextMenu.onTextInput
- || gContextMenu.onImage
- || gContextMenu.onLink
- || gContextMenu.onCanvas
- || gContextMenu.onMathML
- || !this.getDoc().forms
- || !this.getDoc().forms.length) {
- cm0.hidden = true;
- cm1.hidden = true;
- cm5.hidden = true;
- cm6.hidden = true;
- cm7.hidden = true;
- } else {
- if(this.getProfileLabels().length == 1) {
- cm0.hidden = false;
- cm1.hidden = true;
- } else {
- cm0.hidden = true;
- cm1.hidden = false;
- }
- // Show menuseparators if not already separated:
- if(this.isPreviousNodeSeparated(cm5)) {
- cm5.hidden = true;
- } else {
- cm5.hidden = false;
- }
- if(this.isNextNodeSeparated(cm6)) {
- cm6.hidden = true;
- } else {
- cm6.hidden = false;
- }
- cm7.hidden = false;
- }
- cm2.hidden = true;
- cm3.hidden = true;
- cm4.hidden = true;
- this.targetFormField = null;
- }
- },
-
- isNextNodeSeparated: function(node) {
- while(node) {
- node = node.nextSibling
- if(node.hidden) {
- continue;
- }
- if(node.nodeName == 'menuseparator') {
- return true;
- } else {
- return false;
- }
- }
- return true;
- },
-
- isPreviousNodeSeparated: function(node) {
- while(node) {
- node = node.previousSibling;
- if(node.hidden) {
- continue;
- }
- if(node.nodeName == 'menuseparator') {
- return true;
- } else {
- return false;
- }
- }
- return true;
- },
-
- initializePrefs: function() {
- // Initialize the keyboard shortcut object container:
- this.shortcut = new Object();
- this.shortcut['shortcut'] = null;
- this.shortcut['shortcutSubmit'] = null;
- this.shortcut['shortcutAllTabs'] = null;
- this.shortcut['shortcutFromProfileSelection'] = null;
- this.shortcut['shortcutProfile'] = null;
- this.shortcut['shortcutSettings'] = null;
- this.shortcut['shortcutDisplayFormDetails'] = null;
- for(var property in this.shortcut) {
- this.updateShortcut(property);
- }
- // Initialize toolbar and statusbar icons and context menu:
- this.hideToolbarButtonUpdate();
- this.hideToolbarButtonMenuUpdate();
- this.hideStatusbarIconUpdate();
- this.hideContextMenuItemUpdate();
- },
-
- observe: function(subject, topic, data) {
- // Only observe preferences changes:
- if (topic != 'nsPref:changed')
- return;
- switch(data) {
- case 'profileIndex':
- // If set to null, the profileIndex will be updated on next getProfileIndex() call:
- this.profileIndex = null;
- this.tooltipCurrentProfile = null;
- break;
- case 'globalProfileIndex':
- // If set to null, the globalProfileIndex will be updated on next getGlobalProfileIndex() call:
- this.globalProfileIndex = null;
- break;
- case 'formFieldsContextMenuProfileIndex':
- // If set to null, the formFieldsContextMenuProfileIndex will be updated on next getFormFieldsContextMenuProfileIndex() call:
- this.formFieldsContextMenuProfileIndex = null;
- break;
- case 'profileLabels':
- // If set to null, the profileLabels will be updated on next getProfileLabels() call:
- this.profileLabels = null;
- this.tooltipCurrentProfile = null;
- break;
- case 'profileSiteRules':
- // If set to null, the profileSiteRules will be updated on next getProfileSiteRules() call:
- this.profileSiteRules = null;
- break;
- case 'shortcut':
- this.updateShortcut('shortcut');
- this.tooltipGrid = null;
- break;
- case 'shortcutSubmit':
- this.updateShortcut('shortcutSubmit');
- this.tooltipGrid = null;
- break;
- case 'shortcutAllTabs':
- this.updateShortcut('shortcutAllTabs');
- this.tooltipGrid = null;
- break;
- case 'shortcutFromProfileSelection':
- this.updateShortcut('shortcutFromProfileSelection');
- this.tooltipGrid = null;
- break;
- case 'shortcutProfile':
- this.updateShortcut('shortcutProfile');
- this.tooltipGrid = null;
- break;
- case 'shortcutSettings':
- this.updateShortcut('shortcutSettings');
- this.tooltipGrid = null;
- break;
- case 'shortcutDisplayFormDetails':
- this.updateShortcut('shortcutDisplayFormDetails');
- this.tooltipGrid = null;
- break;
- case 'mouseShortcut':
- if(this.mouseButton) {
- this.mouseButton['mouseShortcut'] = null;
- this.tooltipGrid = null;
- }
- break;
- case 'mouseShortcutSubmit':
- if(this.mouseButton) {
- this.mouseButton['mouseShortcutSubmit'] = null;
- this.tooltipGrid = null;
- }
- break;
- case 'mouseShortcutAllTabs':
- if(this.mouseButton) {
- this.mouseButton['mouseShortcutAllTabs'] = null;
- this.tooltipGrid = null;
- }
- break;
- case 'mouseShortcutFromProfileSelection':
- if(this.mouseButton) {
- this.mouseButton['mouseShortcutFromProfileSelection'] = null;
- this.tooltipGrid = null;
- }
- break;
- case 'mouseShortcutProfile':
- if(this.mouseButton) {
- this.mouseButton['mouseShortcutProfile'] = null;
- this.tooltipGrid = null;
- }
- break;
- case 'mouseShortcutSettings':
- if(this.mouseButton) {
- this.mouseButton['mouseShortcutSettings'] = null;
- this.tooltipGrid = null;
- }
- break;
- case 'mouseShortcutDisplayFormDetails':
- if(this.mouseButton) {
- this.mouseButton['mouseShortcutDisplayFormDetails'] = null;
- this.tooltipGrid = null;
- }
- break;
- case 'fieldRules':
- if(!this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- // If set to null, the fieldRules will be updated on next getFieldRules() call:
- this.fieldRules = null;
- }
- break;
- case 'storeEncrypted':
- // To update the stored data, we must decrypt or may not decrypt
- // the prefString in opposition to the setting which just changed -
- // the "invertedSetting" helper var helps to identify this situation:
- this.invertedSetting = true;
- // Store data encrypted/decrypted:
- this.setFieldRules();
- this.invertedSetting = false;
- break;
- case 'dynamicTags':
- // If set to null, the dynamicTags will be updated on next getDynamicTags() call:
- this.dynamicTags = null;
- break;
- case 'dynamicTagCodes':
- // If set to null, the dynamicTagCodes will be updated on next getDynamicTagCodes() call:
- this.dynamicTagCodes = null;
- break;
- case 'hideContextMenuItem':
- this.hideContextMenuItemUpdate();
- break;
- case 'hideFormFieldsContextMenu':
- this.hideContextMenuItemUpdate();
- break;
- case 'hideStatusbarIcon':
- this.hideStatusbarIconUpdate();
- break;
- case 'hideToolbarButton':
- this.hideToolbarButtonUpdate();
- this.hideToolbarButtonMenuUpdate();
- break;
- case 'hideToolbarButtonMenu':
- this.hideToolbarButtonMenuUpdate();
- break;
- case 'useConfigDirectory':
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- this.exportToConfigDirectory();
- } else {
- this.importFromConfigDirectory();
- }
- break;
- }
- },
-
- hideContextMenuItemUpdate: function() {
- var contentAreaContextMenu = document.getElementById('contentAreaContextMenu');
- if(contentAreaContextMenu) {
- if(!this.autofillFormsPrefs.getBoolPref('hideContextMenuItem')
- || !this.autofillFormsPrefs.getBoolPref('hideFormFieldsContextMenu')) {
- // Add the content area context menu listener:
- contentAreaContextMenu.addEventListener(
- 'popupshowing',
- this.contentAreaContextMenuEventListener,
- false
- );
- } else {
- var cm0 = document.getElementById('autofillFormsContextMenuItem');
- var cm1 = document.getElementById('autofillFormsContextMenu');
- var cm2 = document.getElementById('autofillFormsManualFillContextMenu');
- var cm3 = document.getElementById('autofillFormsAddRuleContextMenuItem');
- var cm4 = document.getElementById('autofillFormsAddFormAsProfileContextMenuItem');
- var cm5 = document.getElementById('autofillFormsContextMenuSeparator1');
- var cm6 = document.getElementById('autofillFormsContextMenuSeparator2');
- if(cm0) {
- cm0.hidden = true;
- cm1.hidden = true;
- cm2.hidden = true;
- cm3.hidden = true;
- cm4.hidden = true;
- cm5.hidden = true;
- cm6.hidden = true;
- }
- // Remove the content area context menu listener:
- this.targetFormField = null;
- contentAreaContextMenu.removeEventListener(
- 'popupshowing',
- this.contentAreaContextMenuEventListener,
- false
- );
- }
- }
- },
-
- hideStatusbarIconUpdate: function() {
- // Change the statusbar icon visibility:
- var autofillFormsPanelIcon = document.getElementById('autofillFormsPanelIcon');
- if(autofillFormsPanelIcon) {
- autofillFormsPanelIcon.setAttribute(
- 'hidden',
- this.autofillFormsPrefs.getBoolPref('hideStatusbarIcon')
- );
- }
- },
-
- installToolbarButton: function(buttonID, beforeNodeID, toolbarID) {
- beforeNodeID = beforeNodeID ? beforeNodeID : 'urlbar-container';
- toolbarID = toolbarID ? toolbarID : 'navigation-toolbar';
- if(!document.getElementById(buttonID)) {
- var toolbar = document.getElementById(toolbarID);
- if(!toolbar) {
- // Firefox < 3:
- toolbar = document.getElementById('nav-bar');
- }
- if(toolbar && 'insertItem' in toolbar) {
- var beforeNode = document.getElementById(beforeNodeID);
- if(beforeNode && beforeNode.parentNode != toolbar) {
- beforeNode = null;
- }
- // Insert before the given node or at the end of the toolbar if the node is not available:
- toolbar.insertItem(buttonID, beforeNode, null, false);
- toolbar.setAttribute('currentset', toolbar.currentSet);
- document.persist(toolbar.id, 'currentset');
- }
- }
- },
-
- hideToolbarButtonUpdate: function() {
- var autofillFormsButton = document.getElementById('autofillFormsButton');
- var hideToolbarButton = this.autofillFormsPrefs.getBoolPref('hideToolbarButton');
- if(!autofillFormsButton && !hideToolbarButton) {
- // Add the toolbar button to the toolbar:
- this.installToolbarButton('autofillFormsButton');
- autofillFormsButton = document.getElementById('autofillFormsButton');
- }
- if(autofillFormsButton) {
- autofillFormsButton.setAttribute(
- 'hidden',
- hideToolbarButton
- );
- }
- },
-
- hideToolbarButtonMenuUpdate: function() {
- var autofillFormsButton = document.getElementById('autofillFormsButton');
- if(autofillFormsButton) {
- if(this.autofillFormsPrefs.getBoolPref('hideToolbarButtonMenu')) {
- autofillFormsButton.removeAttribute('type');
- } else {
- autofillFormsButton.setAttribute('type','menu-button');
- }
- }
- },
-
- commandHandler: function(event) {
- if(typeof event.button == 'undefined') {
- // If no event.button is set, the command has been done by the left mouse button:
- event.button = 0;
- }
- // Recognize the mouse button and perform the associated action:
- var mouseButtonObj = this.recognizeMouseButton(event);
- if(this.getMouseButton('mouseShortcut').equals(mouseButtonObj)) {
- this.fillForms();
- } else if(this.getMouseButton('mouseShortcutSubmit').equals(mouseButtonObj)) {
- this.fillForms(null, null, true);
- } else if(this.getMouseButton('mouseShortcutAllTabs').equals(mouseButtonObj)) {
- this.fillForms(null, null, null, true);
- } else if(this.getMouseButton('mouseShortcutFromProfileSelection').equals(mouseButtonObj)) {
- this.profileSelectionFormFillPopup(event);
- } else if(this.getMouseButton('mouseShortcutProfile').equals(mouseButtonObj)) {
- this.showProfileSwitcher(event);
- } else if(this.getMouseButton('mouseShortcutSettings').equals(mouseButtonObj)) {
- this.showDialog('chrome://autofillForms/content/autofillFormsOptions.xul');
- } else if(this.getMouseButton('mouseShortcutDisplayFormDetails').equals(mouseButtonObj)) {
- this.displayFormDetails();
- }
- },
-
- clickHandler: function(event) {
- switch(event.button) {
- case 0:
- // The left mouse button is already handled for clicks on the toolbar button,
- // but not for clicks on the status bar icon:
- if(event.target.id == 'autofillFormsPanelIcon') {
- this.commandHandler(event);
- }
- break;
- default:
- this.commandHandler(event);
- }
- },
-
- profileSelectionFormFillPopup: function(event) {
- var popup = document.getElementById('autofillFormsProfileSelectionPopup');
- if(popup && typeof popup.openPopup == 'function') {
- this.prepareProfileSelectionFormFillMenu(popup);
- // Show the popup menu (only available for Firefox >= 3):
- popup.openPopup(event.target, null, 0, 0, false, true);
- } else {
- this.profileSelectionFormFillPrompt(event);
- }
- },
-
- prepareProfileSelectionFormFillMenu: function(menupopup) {
- // Remove all children nodes:
- while(menupopup.hasChildNodes()) {
- menupopup.removeChild(menupopup.firstChild);
- }
- var menuitem = document.createElement('menuitem');
- menuitem.setAttribute('class','menuitem-iconic autofillFormsIcon');
- // Add the profile labels as menu items:
- for(var i=0; i < this.getProfileLabels().length; i++) {
- menuitem = menuitem.cloneNode(false);
- menuitem.setAttribute('label', this.getProfileLabel(i));
- menuitem.setAttribute('oncommand', 'autofillForms.fillForms(null,'+i+');');
- menupopup.appendChild(menuitem);
- }
- },
-
- profileSelectionFormFillPrompt: function(event) {
- // Show a profile selection prompt and fill out forms with the selected profile:
- var list = this.getProfileLabels();
- var selected = {};
- var ok = this.getPrompts().select(
- window,
- this.getStringBundle().getString('profileSelectionFormFillTitle'),
- this.getStringBundle().getString('profileSelectionPrompt'),
- list.length,
- list,
- selected
- );
- if(ok) {
- this.fillForms(null, selected.value);
- }
- },
-
- fillForms: function(win, profileIndex, autoSubmit, allTabs) {
- if(!win || !win.document) {
- win = this.getWin();
- }
-
- var currentProfileIndex = this.getProfileIndex();
- var toggleAutoSelectBestProfile;
- if(typeof profileIndex == 'number') {
- // Temporarily set the given profile index:
- this.setProfileIndex(profileIndex);
-
- if(this.autofillFormsPrefs.getBoolPref('autoSelectBestProfile')) {
- // Temporarily disable autoSelectBestProfile:
- this.autofillFormsPrefs.setBoolPref('autoSelectBestProfile', false);
- toggleAutoSelectBestProfile = true;
- }
- }
-
- autoSubmit = autoSubmit ? autoSubmit : null;
-
- if(allTabs) {
- // Fill out forms on all open browser tabs:
- for(var i=0; i<this.getBrowser().browsers.length; i++) {
- this.searchAndFillForms(
- this.getBrowser().getBrowserAtIndex(i).contentWindow,
- autoSubmit
- );
- }
- } else {
- // Fill out forms on the current tab (or the given window object):
- this.searchAndFillForms(win, autoSubmit);
- }
-
- // Reset Alternatives (including the cache):
- this.fieldRuleAlternativesIndex = null;
- this.fieldRuleAlternativesLength = null;
- this.fieldRuleAlternativesHash = null;
- this.fieldRuleAlternativesCache = null;
-
- // Reset objects to release used memory:
- this.fieldRules = null;
- this.profileSiteRules = null;
- this.dynamicTags = null;
- this.dynamicTagCodes = null;
-
- // Reset the selected profile:
- this.setProfileIndex(currentProfileIndex);
-
- if(toggleAutoSelectBestProfile) {
- // Reenable autoSelectBestProfile:
- this.autofillFormsPrefs.setBoolPref('autoSelectBestProfile', true);
- }
- },
-
- searchAndFillForms: function(win, autoSubmit) {
- var doc = this.getDoc(win);
-
- // Check if any web forms are available on the current window:
- if(doc && doc.forms && doc.forms.length > 0) {
-
- var url = doc.location.href;
-
- if(this.autofillFormsPrefs.getBoolPref('autoSelectBestProfile')) {
- // Remember the currently selected profile:
- var currentProfileIndex = this.getProfileIndex();
- }
-
- // Select the best matching profile - returns false if none matches:
- if(!this.selectBestMatchingProfile(url)) {
- return;
- }
-
- this.currentWindow = win;
-
- // Holds the form to be submitted:
- var submitForm;
- // Holds the first submit element found on the form:
- var submitElement;
-
- // Go through the forms:
- for(var i = 0; i < doc.forms.length; i++) {
- this.currentFormIndex = i;
-
- // The form elements list:
- var elements = doc.forms[i].elements;
-
- // A hash to store the alternatives for radio input fields:
- this.fieldRuleAlternativesHash = new Object();
-
- // Go through the form elements:
- for(var j = 0; j < elements.length; j++) {
- this.currentElementIndex = j;
-
- // Fill out valid form field types:
- if(this.isValidFormField(elements[j])) {
- this.setFormField(elements[j], url);
- }
-
- // Collect the first submit button of the form if autoSubmit is enabled:
- if(autoSubmit && elements[j].type && elements[j].type == 'submit' && !submitElement) {
- submitElement = elements[j];
- }
- }
-
- this.applyStoredFieldRulesAlternatives();
-
- if(autoSubmit) {
- if(this.lastFormElementMatch && this.lastFormElementMatch.form == doc.forms[i]) {
- // Elements have been matched on this form, check the submitElement:
- if(!submitElement) {
- submitElement = this.getImageSubmitButton(doc.forms[i]);
- }
- submitForm = doc.forms[i];
- // Break out of the forms loop:
- break;
- } else {
- submitElement = null;
- }
- }
- }
-
- if(this.autofillFormsPrefs.getBoolPref('autoSelectBestProfile')) {
- // Reset the selected profile to the manually selected one:
- this.setProfileIndex(currentProfileIndex);
- }
-
- if(this.lastFormElementMatch && this.autofillFormsPrefs.getBoolPref('focusLastFormElementMatch')) {
- // Set the focus to the last matched form element:
- this.lastFormElementMatch.focus();
- }
-
- // Reset the last matched form element:
- this.lastFormElementMatch = null;
-
- this.currentWindow = null;
- this.currentFormIndex = null;
- this.currentElementIndex = null;
-
- if(autoSubmit && submitForm) {
- // autoSubmit the form with a click on the submit button if found
- // or else by calling the submit() method on the form:
- if(submitElement) {
- submitElement.click();
- } else {
- submitForm.submit();
- }
- }
- }
-
- // Recursive call for all subframes:
- for(var f=0; f < win.frames.length; f++) {
- this.searchAndFillForms(win.frames[f], autoSubmit);
- }
- },
-
- getImageSubmitButton: function(form) {
- var inputElements = form.getElementsByTagName('input');
- for(var i = 0; i < inputElements.length; i++) {
- if(inputElements[i].type == 'image') {
- return inputElements[i];
- }
- }
- },
-
- selectBestMatchingProfile: function(url) {
- if(this.autofillFormsPrefs.getBoolPref('autoSelectBestProfile')) {
- var match;
- // The emtpy siteRule (?:) has a match length of 0, so we set the initial value to -1:
- var maxMatch = -1;
- var index = -1;
- // First test the currently selected profile:
- try {
- match = url.match(new RegExp(this.getProfileSiteRule(this.getProfileIndex()),'i'));
- if(match && (match.toString()).length > maxMatch) {
- maxMatch = (match.toString()).length;
- index = this.getProfileIndex();
- }
- } catch(e) {
- // Catch errors caused by invalid profile site rules
- }
- for(var i=0; i<this.getProfileSiteRules().length; i++) {
- if(i == this.getProfileIndex()) {
- // Skip the current profile (already tested):
- continue;
- }
- try {
- match = url.match(new RegExp(this.getProfileSiteRule(i),'i'));
- if(match && (match.toString()).length > maxMatch) {
- maxMatch = (match.toString()).length;
- index = i;
- }
- } catch(e) {
- // Catch errors caused by invalid profile site rules
- }
- }
- if(index > -1) {
- // Select the profile with the best match:
- this.setProfileIndex(index);
- return true;
- }
- } else {
- try {
- var regExp = new RegExp(this.getProfileSiteRule(this.getProfileIndex()),'i');
- if(regExp.test(url)) {
- return true;
- }
- } catch(e) {
- // Catch errors caused by invalid profile site rules
- }
- }
- return false;
- },
-
- setFormField: function(element,url) {
- var matchFound = false;
-
- // Apply the fieldRules of the current profile:
- matchFound = this.applyFieldRulesOnElement(element,url,this.getFieldRules());
-
- // If no match has been found, apply the fieldRules of the global profile, if enabled:
- if(!matchFound && this.autofillFormsPrefs.getBoolPref('enableGlobalProfile')) {
- // Only apply the global profile fieldRules if the current profile is not the global profile;
- if(this.getProfileIndex() != this.getGlobalProfileIndex()) {
- // Only apply the global profile if the global profile site rule matches the url:
- try {
- var regExp = new RegExp(this.getProfileSiteRule(this.getGlobalProfileIndex()),'i');
- if(regExp.test(url)) {
- matchFound = this.applyFieldRulesOnElement(element,url,this.getGlobalFieldRules());
- }
- } catch(e) {
- // Catch errors caused by invalid profile site rules
- }
- }
- }
-
- // Highlight styles:
- var highlightStyleMatch = this.autofillFormsPrefs.getCharPref('highlightStyleMatch');
- var highlightStyleNoMatch = this.autofillFormsPrefs.getCharPref('highlightStyleNoMatch');
-
- if(matchFound) {
- // Set the current element as the last matched form element:
- this.lastFormElementMatch = element;
-
- if(highlightStyleMatch) {
- // Highlight matched form fieds:
- element.setAttribute('style', highlightStyleMatch);
- }
- } else if(highlightStyleNoMatch) {
- // Highlight not matched form fieds:
- element.setAttribute('style', highlightStyleNoMatch);
- }
- },
-
- getIndexForFieldRules: function(fieldRules) {
- if(this.fieldRules) {
- for(var i=0; i<this.fieldRules.length; i++) {
- if(this.fieldRules[i] === fieldRules) {
- return i;
- }
- }
- }
- return -1;
- },
-
- fieldRuleAlternativeFactory: function(fieldRules, index) {
- var af = this;
- if(typeof arguments.callee.fieldRuleAlternative == 'undefined') {
- arguments.callee.fieldRuleAlternative = function(fieldRules, index) {
- this.fieldRules = fieldRules;
- this.index = index;
- this.fieldRule = this.fieldRules[this.index];
- return this;
- }
- arguments.callee.fieldRuleAlternative.prototype = {
- af : af,
- fieldRuleValue: null,
- fieldRuleValueRegExp: null,
- fieldRuleRegExp: null,
- siteRuleRegExp: null,
- optionsIndex: null,
- element: null,
- getValue: function() {
- if(this.fieldRuleValue === null) {
- // Replace dynamic tags if enabled:
- if(this.af.autofillFormsPrefs.getBoolPref('enableDynamicTags'))
- this.fieldRuleValue = this.af.replaceDynamicTags(this.fieldRule['fieldRuleValue']);
- else
- this.fieldRuleValue = this.fieldRule['fieldRuleValue'];
- }
- return this.fieldRuleValue;
- },
- getRule: function() {
- return this.fieldRule['fieldRuleFieldRule'];
- },
- isEnabled: function() {
- return this.fieldRule['fieldRuleEnabled'];
- },
- isURLMatching: function(url) {
- if(this.siteRuleRegExp === null) {
- this.siteRuleRegExp = new RegExp(this.fieldRule['fieldRuleSiteRule'],'i');
- }
- // Test if the siteRule matches the given URL:
- return this.siteRuleRegExp.test(url);
- },
- isRuleMatching: function(str) {
- if(this.fieldRuleRegExp === null) {
- this.fieldRuleRegExp = new RegExp(this.fieldRule['fieldRuleFieldRule'],'i');
- }
- // Test if the fieldRule matches the given string:
- return this.fieldRuleRegExp.test(str);
- },
- isValueMatching: function(str) {
- try {
- if(this.fieldRuleValueRegExp === null) {
- this.fieldRuleValueRegExp = new RegExp(this.getValue(),'i');
- }
- // Test if the value as regular expression matches the given string:
- return this.fieldRuleValueRegExp.test(str);
- } catch(e) {
- // If turning the value into a regular expression fails, compare the strings:
- return (str == this.getValue());
- }
- },
- isOverwrite: function() {
- // This setting defines if existing field contents should be overwritten
- // and if checkboxes and radio buttons should be checked or unchecked
- // and if selection options should be selected or unselected:
- return this.fieldRule['fieldRuleOverwrite']
- },
- getIndex: function() {
- return this.index;
- },
- getOptionsIndex: function() {
- return this.optionsIndex;
- },
- setOptionsIndex: function(optionsIndex) {
- this.optionsIndex = optionsIndex;
- },
- getElement: function() {
- return this.element;
- },
- setElement: function(element) {
- this.element = element;
- },
- clone: function() {
- // This creates only a shallow copy,
- // though we only need a shallow copy:
- var clone = new this.constructor();
- for(var key in this) {
- clone[key] = this[key];
- }
- return clone;
- }
- }
- }
- if(this.fieldRuleAlternativesCache == null) {
- this.fieldRuleAlternativesCache = new Object();
- }
- var identifier = this.getIndexForFieldRules(fieldRules)+'-'+index;
- if(!this.fieldRuleAlternativesCache[identifier]) {
- this.fieldRuleAlternativesCache[identifier] = new arguments.callee.fieldRuleAlternative(
- fieldRules,
- index
- );
- } else {
- // Clone the cached alternative and set the clone as new cached element:
- this.fieldRuleAlternativesCache[identifier] = this.fieldRuleAlternativesCache[identifier].clone()
- }
- return this.fieldRuleAlternativesCache[identifier];
- },
-
- getLabelForElement: function(element) {
- if(element.form && element.id) {
- // Method to retrieve the textual content of the label assigned to the form element:
- var labels = element.form.getElementsByTagName('label');
- for(var i=0; i<labels.length; i++) {
- if(labels[i].htmlFor && labels[i].htmlFor == element.id) {
- // label elements may contain other inline elements,
- // so we just use the innerHTML content and strip it of all HTML tags
- // whitespace is removed from the beginning and end of the string for convenience:
- return this.trim(this.stripTags(labels[i].innerHTML));
- }
- }
- }
- if(!this.autofillFormsPrefs.getBoolPref('labelsStrictMode')) {
- return this.getLabelCloseToElement(element);
- }
- return null;
- },
-
- getLabelCloseToElement: function(element) {
- var label = null;
- var node = element;
- var nextNode;
- if(element.type == 'checkbox' || element.type == 'radio') {
- // For checkboxes and radio buttons the label is usually placed as nextSibling:
- nextNode = 'nextSibling';
- } else {
- // For other elements the label is usually placed as previousSibling:
- nextNode = 'previousSibling';
- }
- // Check if a sibling contains the element label:
- while(node[nextNode]) {
- node = node[nextNode];
- label = this.getNodeTextContent(node, true);
- if(label) {
- return label;
- }
- }
- // Parse the siblings of the parentNode:
- node = element.parentNode;
- if(node) {
- while(node[nextNode]) {
- node = node[nextNode];
- label = this.getNodeTextContent(node, true);
- if(label) {
- return label;
- }
- }
- // If the parentNode of the parentNode is a table cell,
- // also parse the siblings of this node:
- node = element.parentNode.parentNode;
- if(node && node.nodeName == 'TD') {
- while(node[nextNode]) {
- node = node[nextNode];
- label = this.getNodeTextContent(node, true);
- if(label) {
- return label;
- }
- }
- }
- }
- return null;
- },
-
- getNodeTextContent: function(node, trim) {
- // Get the text content from the current node or its child nodes:
- var text;
- if(node.nodeType == 3) {
- // nodeType 3 is a text node:
- text = node.nodeValue;
- } else {
- // Do not follow selection nodes, script nodes or noscript nodes:
- if(node.nodeName == 'SELECT' || node.nodeName == 'SCRIPT' || node.nodeName == 'NOSCRIPT') {
- return '';
- }
- text = '';
- for(var i=0; i<node.childNodes.length; i++) {
- text += this.getNodeTextContent(node.childNodes[i]);
- }
- }
- if(trim) {
- return this.trim(text);
- } else {
- return text;
- }
- },
-
- applyFieldRulesOnElement: function(element,url,fieldRules) {
-
- var labelValue = this.autofillFormsPrefs.getBoolPref('matchAgainstLabels') ?
- this.getLabelForElement(element) : null;
-
- var positionString = this.autofillFormsPrefs.getBoolPref('matchAgainstPositions') ?
- this.currentFormIndex + this.autofillFormsPrefs.getCharPref('positionsIdentifier')
- + this.currentElementIndex : null;
-
- var fieldRuleAlternatives = new Array();
-
- // Go through the list of fieldRules:
- for(var i=0; i < fieldRules.length; i++) {
-
- var rule = this.fieldRuleAlternativeFactory(fieldRules, i);
-
- // Skip this rule if
- // a) the rule is disabled and disabled rules are to be ignored or
- // b) the current URL is not matching the siteRule or
- // c) all of the following are false:
- // 1) the element name does not match the fieldRule
- // 2) label matching is disabled or the element label does not match the fieldRule
- // 3) the element name is not empty or the element id does not match the fieldRule
- // 4) position matching is disabled or the position does not match the fieldRule
- if( !rule.isEnabled() &&
- this.autofillFormsPrefs.getBoolPref('ignoreDisabledRulesOnAutofill') ||
- !rule.isURLMatching(url) ||
- (
- !rule.isRuleMatching(element.name) &&
- (labelValue === null || !rule.isRuleMatching(labelValue)) &&
- (element.name || !rule.isRuleMatching(element.id)) &&
- (positionString === null || !rule.isRuleMatching(positionString))
- )
- ) {
- if(fieldRuleAlternatives.length > 0) {
- // Break out of the loop, if we already have an alternative:
- break;
- } else {
- continue;
- }
- }
-
- if(element.type == 'select-one' || element.type == 'select-multiple') {
- // Go through the selection options:
- for(var j = 0; j < element.options.length; j++) {
- // Match either the value or the text (the selection option label):
- if(rule.isValueMatching(element.options[j].value) || rule.isValueMatching(element.options[j].text)) {
- // Remember the matching option:
- rule.setOptionsIndex(j);
- // Remember the element:
- rule.setElement(element);
- // Add a clone of the alternative and continue to see if the value matches several options:
- fieldRuleAlternatives.push(rule.clone());
- }
- }
- } else if(element.type == 'checkbox' || element.type == 'radio') {
- if(rule.isValueMatching(element.value)) {
- // Remember the element:
- rule.setElement(element);
- // Add the alternative:
- fieldRuleAlternatives.push(rule);
- // Only one rule has to match a checkbox/radio button, so we break out of the loop:
- break;
- }
- } else {
- // Remember the element:
- rule.setElement(element);
- // Add the alternative:
- fieldRuleAlternatives.push(rule);
- }
- }
-
- return this.applyFieldRulesAlternativesOnElement(element,fieldRuleAlternatives);
- },
-
- applyFieldRulesAlternativesOnElement: function(element,fieldRuleAlternatives) {
- if(fieldRuleAlternatives.length == 0) {
- return false;
- }
-
- // Use all alternatives for select-multiple elements:
- if(element.type == 'select-multiple') {
- for(var i=0; i < fieldRuleAlternatives.length; i++) {
- var rule = fieldRuleAlternatives[i];
- if(rule.isOverwrite()) {
- element.options[rule.getOptionsIndex()].selected = true;
- } else {
- element.options[rule.getOptionsIndex()].selected = false;
- }
- }
- return true;
- }
-
- // Select the alternatives index (displays a selection dialog if required):
- var index = this.selectFieldRulesAlternativesIndex(fieldRuleAlternatives);
-
- if(index == -1) {
- return false;
- } else {
- var rule = fieldRuleAlternatives[index];
- if(element.type == 'select-one') {
- if(rule.isOverwrite()) {
- element.options[rule.getOptionsIndex()].selected = true;
- } else {
- element.options[rule.getOptionsIndex()].selected = false;
- }
- } else if(element.type == 'checkbox') {
- if(rule.isOverwrite()) {
- element.checked = true;
- } else {
- element.checked = false;
- }
- } else if(element.type == 'radio') {
- try {
- // Rules matching radio elements are stored and handled as group
- // at the end of each form loop with the applyStoredFieldRulesAlternatives method:
- if(!this.fieldRuleAlternativesHash[element.name]) {
- this.fieldRuleAlternativesHash[element.name] = new Array();
- }
- this.fieldRuleAlternativesHash[element.name].push(rule);
- } catch(e) {
- this.log(e);
- return false;
- }
- } else {
- if(!element.value || rule.isOverwrite()) {
- if(element.type == 'textarea') {
- // Replace control character placeholders:
- element.value = this.replaceControlCharacterPlaceholders(rule.getValue());
- } else {
- element.value = rule.getValue();
- }
- }
- }
- }
- return true;
- },
-
- applyStoredFieldRulesAlternatives: function() {
- for(var key in this.fieldRuleAlternativesHash) {
- var fieldRuleAlternatives = this.filterRealFieldRuleAlternatives(
- this.fieldRuleAlternativesHash[key]
- );
- var index = this.selectFieldRulesAlternativesIndex(fieldRuleAlternatives);
- if(index != -1) {
- var rule = fieldRuleAlternatives[index];
- // This is currently only used for radio input fields:
- if(rule.isOverwrite()) {
- rule.getElement().checked = true;
- } else {
- rule.getElement().checked = false;
- }
- }
- }
- },
-
- filterRealFieldRuleAlternatives: function(fieldRuleAlternatives) {
- // Sort the fieldRuleAlternatives by index:
- fieldRuleAlternatives.sort(this.compareFieldRuleAlternativesByIndex);
- // Make sure only real Alternatives (placed next to each other) are included:
- for(var i=1; i<fieldRuleAlternatives.length; i++) {
- // If the fieldRules index is more than one step larger than the previous one,
- // the remaining array items can be sliced off - they are no real Alternatives:
- if(fieldRuleAlternatives[i].getIndex()-1 > fieldRuleAlternatives[i-1].getIndex()) {
- fieldRuleAlternatives = fieldRuleAlternatives.slice(0, i);
- break;
- }
- }
- return fieldRuleAlternatives;
- },
-
- compareFieldRuleAlternativesByIndex: function(ruleA, ruleB) {
- if(ruleA.getIndex() < ruleB.getIndex()) {
- return -1;
- } else if(ruleA.getIndex() > ruleB.getIndex()) {
- return 1;
- }
- return 0;
- },
-
- getFieldRulesAlternativeLabel: function(rule) {
- // This method returns a label for this alternative
- // to be displayed on the alternatives selection
- switch(rule.getElement().type) {
- case 'select-multiple':
- case 'select-one':
- // Use the options text:
- return rule.getElement().options[rule.getOptionsIndex()].text;
- case 'radio':
- case 'checkbox':
- // Try to retrieve the element label:
- var label = this.getLabelForElement(rule.getElement());
- // Remove the colon, if present:
- if(label && label.charAt(label.length-1) == ':') {
- label = label.substr(0, label.length-1);
- }
- // If no label could be found,
- // use the element value:
- if(!label) {
- label = rule.getElement().value;
- }
- return label;
- default:
- // Use the calculated value:
- return rule.getValue();
- }
- },
-
- selectFieldRulesAlternativesIndex: function(fieldRuleAlternatives) {
- // Display a selection prompt if we have alternatives and no alternativesIndex has been set yet
- // or the rememberAlternativesIndex setting is false or the saved alternativesLength is different:
- if(fieldRuleAlternatives.length > 1) {
- if(this.autofillFormsPrefs.getBoolPref('rememberAlternativesIndex') == false
- || this.fieldRuleAlternativesIndex === null
- || fieldRuleAlternatives.length != this.fieldRuleAlternativesLength) {
- // The selection list displays the index number and the current fieldRuleValues:
- var list = new Array();
- var maxFigureLength = fieldRuleAlternatives.length.toString().length;
- for(var i=0; i < fieldRuleAlternatives.length; i++) {
- list.push(
- this.addLeadingZeros(i+1, maxFigureLength)
- + '. '
- + this.getFieldRulesAlternativeLabel(fieldRuleAlternatives[i])
- );
- }
- var selected = {};
- // Show the selection prompt:
- var ok = this.getPrompts().select(
- window,
- this.getStringBundle().getString('alternativesSelectionWindowTitle'),
- this.getStringBundle().getString('alternativesSelectionPrompt'),
- list.length,
- list,
- selected
- );
- // Save the selected alternatives index, return -1 on cancel:
- if(ok)
- this.fieldRuleAlternativesIndex = selected.value;
- else
- return -1;
-
- this.fieldRuleAlternativesLength = fieldRuleAlternatives.length;
- }
- // Use the fieldRuleAlternative with the selected fieldRuleAlternativesIndex:
- return this.fieldRuleAlternativesIndex;
- } else if(fieldRuleAlternatives.length == 1) {
- return 0
- }
- return -1;
- },
-
- stripTags: function(str) {
- if (!arguments.callee.regExp) {
- arguments.callee.regExp = new RegExp('<\\/?[^>]+?>', 'g');
- }
- // Return string stripped from HTML tags:
- return str.replace(arguments.callee.regExp, '');
- },
-
- trim: function(str) {
- if (!arguments.callee.regExp) {
- arguments.callee.regExp = new RegExp('(?:^\\s+)|(?:\\s+$)', 'g');
- }
- // Return string with whitespace removed at beginning and end of the string:
- return str.replace(arguments.callee.regExp, '');
- },
-
- initProfilesPopupMenu: function(event) {
- var menupopup = event.target;
- // Remove all children nodes:
- while(menupopup.hasChildNodes()) {
- menupopup.removeChild(menupopup.firstChild);
- }
- // Add the profile labels as menu items:
- for(var i=0; i < this.getProfileLabels().length; i++) {
- var menuitem = document.createElement('menuitem');
- menuitem.setAttribute('label', this.getProfileLabel(i));
- menuitem.setAttribute('oncommand', 'autofillForms.setProfileIndex('+i+');');
- menuitem.setAttribute('type', 'radio');
- if(i == this.getProfileIndex()) {
- menuitem.setAttribute('checked', true);
- }
- menupopup.appendChild(menuitem);
- }
- },
-
- initManualFillContextMenu: function(event) {
- var menupopup = event.target;
- // Remove all children nodes:
- while(menupopup.hasChildNodes()) {
- menupopup.removeChild(menupopup.firstChild);
- }
-
- var authenticationNeeded = false;
- if(this.autofillFormsPrefs.getBoolPref('storeEncrypted')) {
- // Determine if a master password is set and the user has not been authenticated yet:
- authenticationNeeded = this.getMasterSecurityDevice().getInternalKeyToken().needsLogin()
- && !this.getMasterSecurityDevice().getInternalKeyToken().isLoggedIn();
- }
-
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- // Always retrieve the profile labels from file if useConfigDirectory is enabled:
- this.profileLabels = null;
- }
-
- // Check if only one profile is to be shown:
- if((this.getFormFieldsContextMenuProfileIndex() != -3) || (this.getProfileLabels().length == 1)) {
- var profileIndex = (this.getFormFieldsContextMenuProfileIndex() == -2)
- ? this.getProfileIndex() : this.getFormFieldsContextMenuProfileIndex();
- if(authenticationNeeded) {
- var menuitem = document.createElement('menuitem');
- menuitem.setAttribute('label', this.getProfileLabel(profileIndex)+'...');
- menuitem.setAttribute(
- 'oncommand',
- 'autofillForms.authenticateAndShowManualFillDialog('+profileIndex+');'
- );
- menupopup.appendChild(menuitem);
- } else {
- this.initManualFillProfileContextMenu(event, profileIndex);
- }
- return;
- }
-
- // Add the profile labels as menus or menuitems if authentication is needed:
- for(var i=0; i < this.getProfileLabels().length; i++) {
- if(authenticationNeeded) {
- var menuitem = document.createElement('menuitem');
- menuitem.setAttribute('label', this.getProfileLabel(i)+'...');
- menuitem.setAttribute(
- 'oncommand',
- 'autofillForms.authenticateAndShowManualFillDialog('+i+');'
- );
- menupopup.appendChild(menuitem);
- } else {
- var menu = document.createElement('menu');
- menu.setAttribute('label', this.getProfileLabel(i));
-
- // Add a menupopup for each profile:
- var profilemenupopup = document.createElement('menupopup');
- profilemenupopup.setAttribute(
- 'onpopupshowing',
- 'if(event.target == this) autofillForms.initManualFillProfileContextMenu(event, '+i+');'
- );
- menu.appendChild(profilemenupopup);
- menupopup.appendChild(menu);
- }
- }
- },
-
- initManualFillProfileContextMenu: function(event, profileID) {
- var menupopup = event.target;
- // Remove all children nodes:
- while(menupopup.hasChildNodes()) {
- menupopup.removeChild(menupopup.firstChild);
- }
- var menuPopupMore;
- // Add the profile field rules as menu items:
- for(var i=0; i < this.getFieldRules(profileID).length; i++) {
- var menuitem = document.createElement('menuitem');
- menuitem.setAttribute('label', this.getFieldRules(profileID)[i]['fieldRuleName']);
- menuitem.setAttribute('oncommand', 'autofillForms.fillTargetFormField('+profileID+','+i+');');
- if(this.getFieldRules(profileID)[i]['fieldRuleEnabled']) {
- menupopup.appendChild(menuitem);
- } else {
- // Add disabled items to a "More..." menu:
- if(!menuPopupMore) {
- menuPopupMore = document.createElement('menupopup');
- }
- menuPopupMore.appendChild(menuitem);
- }
- }
- if(menuPopupMore) {
- if(!menupopup.hasChildNodes()) {
- // All field rules of this profile are disabled, so no need to create a submenu:
- while(menuPopupMore.hasChildNodes()) {
- // appendChild removes the node from the current parent node
- // and adds it to the new parent node:
- menupopup.appendChild(menuPopupMore.firstChild);
- }
- } else {
- // Append the "More..." menu:
- var menuMore = document.createElement('menu');
- menuMore.setAttribute('label', this.getStringBundle().getString('contextMenuMore'));
- menuMore.appendChild(menuPopupMore);
- menupopup.appendChild(menuMore);
- }
- }
- // Reset object to release used memory:
- this.fieldRules = null;
- },
-
- authenticateAndShowManualFillDialog: function(profileID) {
- try {
- Components.classes['@mozilla.org/security/pk11tokendb;1']
- .getService(Components.interfaces.nsIPK11TokenDB).getInternalKeyToken().login(false);
-
- var prompts = Components.classes['@mozilla.org/embedcomp/prompt-service;1']
- .getService(Components.interfaces.nsIPromptService);
- // The selection and the subselection lists:
- var list = new Array();
- var listMore;
- // Hashs mapping the list positions to the original indices:
- var listIndexMapping = new Object();;
- var listMoreIndexMapping;
- for(var i=0; i < this.getFieldRules(profileID).length; i++) {
- if(this.getFieldRules(profileID)[i]['fieldRuleEnabled']) {
- list.push(this.getFieldRules(profileID)[i]['fieldRuleName']);
- listIndexMapping[list.length-1] = i;
- } else {
- // Add disabled items to a "More..." list:
- if(!listMore) {
- listMore = new Array();
- listMoreIndexMapping = new Object();
- }
- listMore.push(this.getFieldRules(profileID)[i]['fieldRuleName']);
- listMoreIndexMapping[listMore.length-1] = i;
- }
- }
- if(listMore) {
- // If all field rules of this profile are disabled, there is no need of a sublist:
- if(!list.length) {
- list = listMore;
- listIndexMapping = listMoreIndexMapping;
- listMore = null;
- listMoreIndexMapping = null;
- } else {
- list.push(this.getStringBundle().getString('contextMenuMore'));
- }
- }
- var selected = {};
- var ok = Components.classes['@mozilla.org/embedcomp/prompt-service;1']
- .getService(Components.interfaces.nsIPromptService)
- .select(
- window,
- null, // Window title - defaults to locale version of "Select"
- null, // Prompt text - defaults to empty string
- list.length,
- list,
- selected
- );
- if(ok) {
- // If "More..." is selected, show the disabled items as selection list:
- if(listMore && selected.value == list.length-1) {
- selected = {};
- ok = Components.classes['@mozilla.org/embedcomp/prompt-service;1']
- .getService(Components.interfaces.nsIPromptService)
- .select(
- window,
- null, // Window title - defaults to locale version of "Select"
- null, // Prompt text - defaults to empty string
- listMore.length,
- listMore,
- selected
- );
- if(ok) {
- this.fillTargetFormField(
- profileID,
- listMoreIndexMapping[selected.value]
- );
- }
- } else {
- this.fillTargetFormField(
- profileID,
- listIndexMapping[selected.value]
- );
- }
- }
- } catch(e) {
- // Authentication with master security device failed
- }
- // Reset object to release used memory:
- this.fieldRules = null;
- },
-
- fillTargetFormField: function(profileID, ruleID) {
- if(this.targetFormField) {
- var value = this.getFieldRules(profileID)[ruleID]['fieldRuleValue'];
- // Replace dynamic tags if enabled:
- if(this.autofillFormsPrefs.getBoolPref('enableDynamicTags')) {
- value = this.replaceDynamicTags(value);
- }
- try {
- // Try to use selection information:
- var newCursorPos = this.targetFormField.selectionStart + value.length;
- this.targetFormField.value = this.targetFormField.value.substr(0, this.targetFormField.selectionStart)
- + value
- + this.targetFormField.value.substr(this.targetFormField.selectionEnd);
- // Adjust the cursor position:
- this.targetFormField.selectionEnd = newCursorPos;
- this.targetFormField.selectionStart = newCursorPos;
- } catch(e) {
- // This input field does not support selections - just try to set the value:
- try {
- this.targetFormField.value = value;
- } catch(e) {
- // Catch errors if value could not be set on the form field
- }
- }
- // Reset objects to release used memory:
- this.fieldRules = null;
- this.dynamicTags = null;
- this.dynamicTagCodes = null;
- }
- },
-
- tooltip: function(event) {
- if (!document.tooltipNode) {
- return;
- }
- // Get the tooltip node:
- var tooltip = document.getElementById('autofillFormsTooltip');
- if(tooltip) {
- // Add the associated tooltip content for each toolbar button menu item, toolbar button and statusbar icon:
- if(document.tooltipNode.id == 'autofillFormsButton' || document.tooltipNode.id == 'autofillFormsPanelIcon') {
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- // Always retrieve the profile labels from file if useConfigDirectory is enabled:
- this.profileLabels = null;
- this.tooltipCurrentProfile = null;
- }
- if(!this.tooltipCurrentProfile || !this.tooltipGrid) {
- // Remove all children nodes:
- while(tooltip.hasChildNodes()) {
- tooltip.removeChild(tooltip.firstChild);
- }
- // Add the current profile label:
- tooltip.appendChild(this.getTooltipCurrentProfile());
- // Add the tooltip grid with the command labels, mouse buttons and keyboard shortcuts:
- tooltip.appendChild(this.getTooltipGrid());
- }
- } else {
- // Don't show tooltips for the toolbar button menu items:
- event.preventDefault();
- }
- }
- },
-
- getTooltipCurrentProfile: function() {
- if(!this.tooltipCurrentProfile) {
- var hbox = document.createElement('hbox');
- hbox.setAttribute(
- 'id',
- 'autofillFormsTooltipCurrentProfile'
- );
- var label = document.createElement('label');
- label.setAttribute(
- 'value',
- this.getStringBundle().getString('currentProfileLabel')
- );
- label.setAttribute(
- 'id',
- 'autofillFormsTooltipCurrentProfileCaption'
- );
- hbox.appendChild(label);
- label = label.cloneNode(false);
- label.setAttribute(
- 'value',
- this.getProfileLabel(this.getProfileIndex())
- );
- label.setAttribute(
- 'id',
- 'autofillFormsTooltipCurrentProfileLabel'
- );
- hbox.appendChild(label);
- this.tooltipCurrentProfile = hbox;
- }
- return this.tooltipCurrentProfile;
- },
-
- getTooltipGrid: function() {
- if(!this.tooltipGrid) {
- var commands = new Array();
- for(var property in this.shortcut) {
- commands.push(new Array(
- this.getStringBundle().getString('tooltip'+property.replace(/shortcut/,'')),
- this.getFormattedMouseButton(this.getMouseButton('mouseS'+property.substr(1))),
- this.getFormattedShortcut(this.getShortcut(property))
- ));
- }
- var grid = document.createElement('grid');
- grid.setAttribute(
- 'id',
- 'autofillFormsTooltipGrid'
- );
- var columns = document.createElement('columns');
- var column = document.createElement('column');
- var rows = document.createElement('rows');
- var row = document.createElement('row');
- var label = document.createElement('label');
- columns.appendChild(column);
- columns.appendChild(column.cloneNode(false));
- columns.appendChild(column.cloneNode(false));
- grid.appendChild(columns);
- // Create the column headers:
- label.setAttribute(
- 'class',
- 'autofillFormsTooltipGridHeader'
- );
- label.setAttribute(
- 'value',
- this.getStringBundle().getString('command')
- );
- row.appendChild(label);
- label = label.cloneNode(false);
- label.setAttribute(
- 'value',
- this.getStringBundle().getString('mousebutton')
- );
- row.appendChild(label);
- label = label.cloneNode(false);
- label.setAttribute(
- 'value',
- this.getStringBundle().getString('keyboardShortcut')
- );
- row.appendChild(label);
- rows.appendChild(row);
- // Create a row for each command:
- for(var i=0; i<commands.length; i++) {
- row = row.cloneNode(false);
- // Skip if neither mouseButton nor keyboard shortcut is set:
- if(!commands[i][1] && !commands[i][2]) {
- continue;
- }
- for(var j=0; j<commands[i].length; j++) {
- label = label.cloneNode(false);
- label.setAttribute(
- 'value',
- commands[i][j]
- );
- if(j == 0) {
- label.setAttribute(
- 'class',
- 'autofillFormsTooltipGridCommand'
- );
- } else if(j == 1) {
- label.setAttribute(
- 'class',
- 'autofillFormsTooltipGridMouseButton'
- );
- } else {
- label.setAttribute(
- 'class',
- 'autofillFormsTooltipGridKeyboardShortcut'
- );
- }
- row.appendChild(label);
- }
- rows.appendChild(row);
- }
- grid.appendChild(rows);
- this.tooltipGrid = grid;
- }
- return this.tooltipGrid;
- },
-
- resetAllProfiles: function() {
- if(this.autofillFormsPrefs.getBoolPref('enableConfirmationDialogs')) {
- // Confirmation dialog:
- if(!this.getPrompts().confirm(
- null,
- this.getStringBundle().getString('resetAllProfilesTitle'),
- this.getStringBundle().getString('resetAllProfilesText')
- )
- ) {
- return;
- }
- }
-
- // Reset the user preferences:
- if(this.autofillFormsPrefs.prefHasUserValue('useConfigDirectory')) {
- this.autofillFormsPrefs.clearUserPref('useConfigDirectory');
- }
- if(this.autofillFormsPrefs.prefHasUserValue('storeEncrypted')) {
- this.autofillFormsPrefs.clearUserPref('storeEncrypted');
- }
- if(this.autofillFormsPrefs.prefHasUserValue('profileIndex')) {
- this.autofillFormsPrefs.clearUserPref('profileIndex');
- }
- if(this.autofillFormsPrefs.prefHasUserValue('profileLabels')) {
- this.autofillFormsPrefs.clearUserPref('profileLabels');
- }
- if(this.autofillFormsPrefs.prefHasUserValue('profileSiteRules')) {
- this.autofillFormsPrefs.clearUserPref('profileSiteRules');
- }
- if(this.autofillFormsPrefs.prefHasUserValue('fieldRules')) {
- this.autofillFormsPrefs.clearUserPref('fieldRules');
- }
-
- this.profileIndex = null;
- this.profileLabels = null;
- this.profileSiteRules = null;
- this.fieldRules = null;
-
- // Re-init the profiles lists:
- this.initProfilesLists();
- // Re-init the fieldRules tree:
- this.initTree();
- // Re-initialize the simple interface:
- this.initSimpleInterface();
-
- if(this.tree && this.selection) {
- try {
- // Clear out the fieldRules tree selections
- this.selection.select(-1);
- } catch(e) {
- this.log(e);
- }
- }
- },
-
- initProfilesLists: function(event) {
- // The profiles tree:
- this.initProfilesTree();
-
- // Editable profiles menu list:
- var profilesMenuList = document.getElementById('profilesMenuList');
- if(profilesMenuList) {
- profilesMenuList.removeAllItems();
- for(var i=0; i < this.getProfileLabels().length; i++) {
- profilesMenuList.appendItem(
- this.getProfileLabel(i)
- );
- }
- profilesMenuList.selectedIndex = this.getProfileIndex();
- }
- // Simple interface profiles menu list:
- var simpleInterfaceProfileMenuList = document.getElementById('simpleInterfaceProfileMenuList');
- if(simpleInterfaceProfileMenuList) {
- simpleInterfaceProfileMenuList.removeAllItems();
- for(var i=0; i < this.getProfileLabels().length; i++) {
- simpleInterfaceProfileMenuList.appendItem(
- this.getProfileLabel(i)
- );
- }
- simpleInterfaceProfileMenuList.selectedIndex = this.getProfileIndex();
- }
- // Global profile selection:
- var globalProfileMenuList = document.getElementById('globalProfileMenuList');
- if(globalProfileMenuList) {
- globalProfileMenuList.removeAllItems();
- for(var i=0; i < this.getProfileLabels().length; i++) {
- globalProfileMenuList.appendItem(
- this.getProfileLabel(i)
- );
- }
- globalProfileMenuList.selectedIndex = this.getGlobalProfileIndex();
- }
- // Form fields context menu selection:
- var contextMenuProfileMenuList = document.getElementById('contextMenuProfileMenuList');
- if(contextMenuProfileMenuList) {
- // The first 3 items are "All profiles", "Active profile" and a menuseparator:
- while(contextMenuProfileMenuList.firstChild.childNodes[3]) {
- // The more convenient getItemAtIndex does not seem to work with Firefox versions < 3,
- // so we use DOM methods on the menupopup child node of the menu node instead:
- contextMenuProfileMenuList.firstChild.removeChild(
- contextMenuProfileMenuList.firstChild.childNodes[3]
- );
- }
- for(var i=0; i < this.getProfileLabels().length; i++) {
- contextMenuProfileMenuList.appendItem(
- this.getProfileLabel(i)
- );
- }
- contextMenuProfileMenuList.selectedIndex
- = this.getFormFieldsContextMenuProfileIndex()+3;
- }
-
- // The profile site rule textbox:
- this.initProfileSiteRuleTextBox();
- },
-
- updateProfilesLists: function() {
- // The more convenient getItemAtIndex does not seem to work with Firefox versions < 3,
- // so we use DOM methods on the menupopup child node of the menu nodes instead:
-
- // Editable profiles menu list:
- var profilesMenuList = document.getElementById('profilesMenuList');
- if(profilesMenuList) {
- profilesMenuList
- .firstChild.childNodes[this.getProfileIndex()].label
- = this.getProfileLabel(this.getProfileIndex());
- }
- // Simple interface profiles menu list:
- var simpleInterfaceProfileMenuList = document.getElementById('simpleInterfaceProfileMenuList');
- if(simpleInterfaceProfileMenuList) {
- simpleInterfaceProfileMenuList
- .firstChild.childNodes[this.getProfileIndex()].label
- = this.getProfileLabel(this.getProfileIndex());
- }
- // Global profile selection:
- var globalProfileMenuList = document.getElementById('globalProfileMenuList');
- if(globalProfileMenuList) {
- globalProfileMenuList
- .firstChild.childNodes[this.getProfileIndex()].label
- = this.getProfileLabel(this.getProfileIndex());
- }
- // Form fields context menu selection:
- var contextMenuProfileMenuList = document.getElementById('contextMenuProfileMenuList');
- if(contextMenuProfileMenuList) {
- // The first 3 items are "All profiles", "Active profile" and a menuseparator:
- contextMenuProfileMenuList
- .firstChild.childNodes[this.getProfileIndex()+3].label
- = this.getProfileLabel(this.getProfileIndex());
- }
- // The profiles tree:
- if(this.profilesTreeBox) {
- this.profilesTreeBox.invalidateRow(this.getProfileIndex());
- }
- },
-
- getProfileIndex: function() {
- if(this.profileIndex == null)
- this.profileIndex = this.autofillFormsPrefs.getIntPref('profileIndex');
- return this.profileIndex;
- },
-
- setProfileIndex: function(index) {
- if(this.profileIndex == index)
- return;
-
- // See method selectedFieldRule() why this has to be set to null:
- this.lastSelectedIndex = null;
-
- this.autofillFormsPrefs.setIntPref('profileIndex',parseInt(index));
- // Update the tree view if present:
- if(this.tree) {
- // The settings page doesn't observe preferences changes - set the profileIndex manually:
- this.profileIndex = index;
- // Re-init the tree:
- this.initTree();
- // Re-initialize the simple interface:
- this.initSimpleInterface();
- }
- // Update the profiles tree selection if present and not already updated:
- if(this.profilesTree && this.profilesSelection.currentIndex != index) {
- // Select the current profile:
- this.profilesSelection.select(index);
-
- // Ensure row is visible (scrolls if not):
- this.profilesTreeBox.ensureRowIsVisible(index);
- }
- // Editable profiles menu list:
- var profilesMenuList = document.getElementById('profilesMenuList');
- if(profilesMenuList) {
- profilesMenuList.selectedIndex = this.getProfileIndex();
- }
- // Simple interface profiles menu list:
- var simpleInterfaceProfileMenuList = document.getElementById('simpleInterfaceProfileMenuList');
- if(simpleInterfaceProfileMenuList) {
- simpleInterfaceProfileMenuList.selectedIndex = this.getProfileIndex();
- }
-
- // The profile site rule textbox:
- this.initProfileSiteRuleTextBox();
- },
-
- getGlobalProfileIndex: function() {
- if(this.globalProfileIndex == null) {
- this.globalProfileIndex = this.autofillFormsPrefs.getIntPref('globalProfileIndex');
- }
- return this.globalProfileIndex;
- },
-
- setGlobalProfileIndex: function(index) {
- if(this.globalProfileIndex == index) {
- return;
- }
- this.autofillFormsPrefs.setIntPref('globalProfileIndex',parseInt(index));
- // The settings page doesn't observe preferences changes - set the profileIndex manually:
- this.globalProfileIndex = index;
- },
-
- getFormFieldsContextMenuProfileIndex: function() {
- if(this.formFieldsContextMenuProfileIndex == null) {
- this.formFieldsContextMenuProfileIndex
- = this.autofillFormsPrefs.getIntPref('formFieldsContextMenuProfileIndex');
- }
- return this.formFieldsContextMenuProfileIndex;
- },
-
- setFormFieldsContextMenuProfileIndex: function(index) {
- if(this.formFieldsContextMenuProfileIndex == index) {
- return;
- }
- this.autofillFormsPrefs.setIntPref('formFieldsContextMenuProfileIndex',parseInt(index));
- // The settings page doesn't observe preferences changes - set the profileIndex manually:
- this.formFieldsContextMenuProfileIndex = index;
- },
-
- getProfileLabelsFile: function() {
- var file = this.getConfigDirectory();
- file.append('profileLabels.txt');
- if(!file.exists()) {
- file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0660);
- }
- return file;
- },
-
- exportProfileLabelsToConfigDirectory: function() {
- var prefString;
- // Get the profileLabels string from the preferences:
- prefString = this.autofillFormsPrefs
- .getComplexValue('profileLabels',Components.interfaces.nsIPrefLocalizedString)
- .data;
- if(prefString) {
- this.setFileContent(this.getProfileLabelsFile(), prefString);
- }
- },
-
- importProfileLabelsFromConfigDirectory: function() {
- var prefString;
- prefString = this.getFileContent(this.getProfileLabelsFile());
- if(prefString) {
- // Store the profileLabels as unicode string in the preferences:
- this.autofillFormsPrefs.setComplexValue(
- 'profileLabels',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(prefString)
- );
- }
- },
-
- getProfileLabels: function() {
- if(this.profileLabels == null) {
- var prefString;
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- // Get the profileLabels string from the profileLabels file in the configDirectory:
- prefString = this.getFileContent(this.getProfileLabelsFile());
- }
- if(!prefString) {
- prefString = this.autofillFormsPrefs
- .getComplexValue('profileLabels',Components.interfaces.nsIPrefLocalizedString)
- .data;
- }
- // The profile labels are stored as a string with tabs as separators:
- this.profileLabels = prefString.split('\t');
- }
- return this.profileLabels;
- },
-
- setProfileLabels: function(profileLabels) {
- // Save the profile labels separated by tabs:
- var prefString = profileLabels.join('\t');
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- this.setFileContent(this.getProfileLabelsFile(), prefString);
- } else {
- this.autofillFormsPrefs.setComplexValue(
- 'profileLabels',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(prefString)
- );
- }
- },
-
- getProfileLabel: function(index) {
- while(this.getProfileLabels().length <= index) {
- this.getProfileLabels().push(this.getUniqueProfileLabel());
- }
- return this.getProfileLabels()[index];
- },
-
- setProfileLabel: function(index, label) {
- while(this.getProfileLabels().length <= index) {
- this.getProfileLabels().push(this.getUniqueProfileLabel());
- }
- this.getProfileLabels()[index] = label;
- // Save the profileLabels list in the preferences:
- this.setProfileLabels(this.getProfileLabels());
- },
-
- getUniqueProfileLabel: function(profileLabel) {
- if(!profileLabel) {
- profileLabel = 'Profile';
- }
-
- // Make sure the profile label is unique:
- if(!this.inArray(this.getProfileLabels(), profileLabel)) {
- return profileLabel;
- }
- var i = profileLabel.lastIndexOf(' ');
- var n = parseInt(profileLabel.substr(i+2));
- if(isNaN(n)) {
- return this.getUniqueProfileLabel(profileLabel+' (2)');
- }
- n++;
- profileLabel = profileLabel.substr(0, i)+' ('+n+')';
- return this.getUniqueProfileLabel(profileLabel);
- },
-
- changeProfileLabel: function(newProfileLabel) {
- var profilesMenuList = document.getElementById('profilesMenuList');
- if(profilesMenuList) {
- // Make sure the new profile label is safe and unique:
- newProfileLabel = this.getUniqueProfileLabel(this.makeSafe(newProfileLabel));
- // Update the label of the selected profile:
- this.setProfileLabel(this.getProfileIndex(), newProfileLabel);
- // Update the profiles textbox contents:
- profilesMenuList.inputField.value = newProfileLabel;
- document.getElementById('profileLabelTextBox').value = newProfileLabel;
- // Update the profiles lists:
- this.updateProfilesLists();
- }
- },
-
- initProfileSiteRuleTextBox: function(event) {
- var profileSiteRuleTextBox = document.getElementById('profileSiteRuleTextBox');
- if(profileSiteRuleTextBox) {
- profileSiteRuleTextBox.value = this.getProfileSiteRule(this.getProfileIndex());
- }
- },
-
- changeProfileSiteRule: function(siteRule) {
- var profileSiteRuleTextBox = document.getElementById('profileSiteRuleTextBox');
- if(profileSiteRuleTextBox) {
- // Check the regular expression before updating the profile site rules:
- try {
- siteRule = this.getRegExpStr(
- this.makeSafe(siteRule)
- );
- profileSiteRuleTextBox.value = siteRule;
- document.getElementById('profileSiteRuleTextBox2').value = siteRule;
-
- var newProfileSiteRules = this.getProfileSiteRules();
- newProfileSiteRules[this.getProfileIndex()] = siteRule;
- this.setProfileSiteRules(newProfileSiteRules);
-
- // Update the profiles tree:
- if(this.profilesTreeBox) {
- this.profilesTreeBox.invalidateRow(this.getProfileIndex());
- }
- } catch(e) {
- this.invalidRegExpAlert(e);
- }
- }
- },
-
- getProfileSiteRulesFile: function() {
- var file = this.getConfigDirectory();
- file.append('profileSiteRules.txt');
- if(!file.exists()) {
- file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0660);
- }
- return file;
- },
-
- exportProfileSiteRulesToConfigDirectory: function() {
- var prefString;
- // Get the profileSiteRules string from the preferences:
- prefString = this.autofillFormsPrefs
- .getComplexValue('profileSiteRules',Components.interfaces.nsISupportsString)
- .data;
- if(prefString) {
- this.setFileContent(this.getProfileSiteRulesFile(), prefString);
- }
- },
-
- importProfileSiteRulesFromConfigDirectory: function() {
- var prefString;
- prefString = this.getFileContent(this.getProfileSiteRulesFile());
- if(prefString) {
- // Store the profileSiteRules as unicode string in the preferences:
- this.autofillFormsPrefs.setComplexValue(
- 'profileSiteRules',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(prefString)
- );
- }
- },
-
- getProfileSiteRules: function() {
- if(this.profileSiteRules == null) {
- var prefString;
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- // Get the profileSiteRules string from the profileSiteRules file in the configDirectory:
- prefString = this.getFileContent(this.getProfileSiteRulesFile());
- }
- if(!prefString) {
- prefString = this.autofillFormsPrefs
- .getComplexValue('profileSiteRules',Components.interfaces.nsISupportsString)
- .data;
- }
- // The profile SiteRules are stored as a string with tabs as separators:
- this.profileSiteRules = prefString.split('\t');
- }
- return this.profileSiteRules;
- },
-
- setProfileSiteRules: function(profileSiteRules) {
- // Save the profile SiteRules separated by tabs:
- var prefString = profileSiteRules.join('\t');
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- this.setFileContent(this.getProfileSiteRulesFile(), prefString);
- } else {
- this.autofillFormsPrefs.setComplexValue(
- 'profileSiteRules',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(prefString)
- );
- }
- },
-
- getProfileSiteRule: function(index) {
- while(this.getProfileSiteRules().length <= index) {
- this.getProfileSiteRules().push('(?:)');
- }
- return this.getProfileSiteRules()[index];
- },
-
- setProfileSiteRule: function(index, siteRule) {
- while(this.getProfileSiteRules().length <= index) {
- this.getProfileSiteRules().push('(?:)');
- }
- this.getProfileSiteRules()[index] = siteRule;
- // Save the profileSiteRules in the preferences:
- this.setProfileSiteRules(this.getProfileSiteRules());
- },
-
- addFormAsProfile: function(event) {
- if(this.targetFormField && this.targetFormField.form) {
- var elements = this.targetFormField.form.elements;
- var doc = this.targetFormField.form.ownerDocument;
-
- var newProfile = new Array();
-
- // Go through the form elements:
- for(var i=0; i<elements.length; i++) {
- // Only use valid form fields:
- if(this.isValidFormField(elements[i])) {
- var value;
- var overwrite = true;
-
- // Create the fieldRule (from name, label or id):
- var fieldRule = this.getFieldRuleForElement(elements[i]);
-
- switch(elements[i].type) {
- case 'checkbox':
- // Add a rule to uncheck the checkbox if it is unchecked:
- if(!elements[i].checked) {
- overwrite = false;
- }
- value = this.getRegExpStrForValue(elements[i].value);
- break;
- case 'radio':
- // Only add checked radio buttons:
- if(!elements[i].checked) {
- continue;
- }
- value = this.getRegExpStrForValue(elements[i].value);
- break;
- case 'select-one':
- value = this.getRegExpStrForValue(elements[i].value);
- break;
- case 'select-multiple':
- var fieldRuleLabel = this.makeSafe(this.getFieldRuleNameForElement(elements[i]));
- // Add all options as fieldRules, set "overwrite" to true if selected:
- for(var j = 0; j < elements[i].options.length; j++) {
- newProfile.push(
- this.createFieldRule(
- fieldRuleLabel+' ('+j+')',
- this.getRegExpStrForValue(elements[i].options[j].value),
- fieldRule,
- '(?:)',
- elements[i].options[j].selected,
- true
- )
- );
- }
- continue;
- default:
- value = this.makeSafe(this.replaceControlCharacters(elements[i].value));
- break;
- }
-
- // Add the current element as new rule to the profile list:
- newProfile.push(
- this.createFieldRule(
- this.makeSafe(this.getFieldRuleNameForElement(elements[i])),
- value,
- fieldRule,
- '(?:)',
- overwrite,
- true
- )
- );
- }
- }
-
- // Initialize the fieldRules:
- this.getFieldRules();
-
- // Add the new profile to the fieldRules:
- this.fieldRules.push(newProfile);
- // Save the profiles in the preferences:
- this.setFieldRules();
-
- // Add a label for default empty profile:
- if(this.getProfileLabels().length == 0) {
- this.getProfileLabels().push(this.getUniqueProfileLabel());
- }
- // Use the documents hostname as profile label and add it to the profile labels list:
- this.getProfileLabels().push(this.getUniqueProfileLabel(this.makeSafe(doc.location.host)));
- // Save the profileLabels list in the preferences:
- this.setProfileLabels(this.getProfileLabels());
-
- // Use the protocol and domain of the web form as profile siteRule:
- this.getProfileSiteRules().push(this.getSiteRuleForURL(doc.location.protocol+'//'+doc.location.host));
- // Save the profileSiteRules in the preferences:
- this.setProfileSiteRules(this.getProfileSiteRules());
-
- // Save the the new profile index as selected profileIndex:
- this.setProfileIndex(this.getProfileLabels().length-1);
-
- // Reset the target form field:
- this.targetFormField = null;
-
- // Create parameters for the settings page:
- var params = new Object();
- params.newProfileFromForm = true;
-
- // Open up the settings page:
- this.showDialog('chrome://autofillForms/content/autofillFormsOptions.xul', params);
- }
- },
-
- addProfile: function(newProfileLabel) {
- // Duplicate the selected profile (do a deep copy):
- this.fieldRules.push(
- this.copyFieldRules(this.getFieldRules())
- );
- // Save the profiles in the preferences:
- this.setFieldRules();
- // Add profile label for default empty profile:
- if(this.getProfileLabels().length == 0) {
- this.getProfileLabels().push(this.getUniqueProfileLabel());
- }
- // Add the (unique) newProfileLabel to the profileLabels list:
- this.getProfileLabels().push(this.getUniqueProfileLabel(this.makeSafe(newProfileLabel)));
- // Save the profileLabels list in the preferences:
- this.setProfileLabels(this.getProfileLabels());
- // Add a new empty profileSiteRule:
- this.getProfileSiteRules().push('(?:)');
- // Save the profileSiteRules in the preferences:
- this.setProfileSiteRules(this.getProfileSiteRules());
- // Save the the new profile index as selected profileIndex:
- this.setProfileIndex(this.getProfileLabels().length-1);
- // Update the profiles lists:
- this.initProfilesLists();
- // Re-init the fieldRules tree:
- this.initTree();
- // Re-initialize the simple interface:
- this.initSimpleInterface();
- },
-
- removeProfile: function(event) {
- if(this.autofillFormsPrefs.getBoolPref('enableConfirmationDialogs')) {
- // Confirmation dialog:
- if(!this.getPrompts().confirm(
- null,
- this.getStringBundle().getString('removeProfileTitle'),
- this.getStringBundle().getString('removeProfileText')
- )
- ) {
- return;
- }
- }
-
- // Remove the selected profile from the list:
- this.fieldRules.splice(this.getProfileIndex(),1);
- // Save the profiles in the preferences:
- this.setFieldRules();
- // Remove the selected profile from the profileLabels list:
- this.getProfileLabels().splice(this.getProfileIndex(),1);
- // Save the profileLabels list in the preferences:
- this.setProfileLabels(this.getProfileLabels());
- // Remove the selected profile's siteRule:
- this.getProfileSiteRules().splice(this.getProfileIndex(),1);
- // Save the profileSiteRules in the preferences:
- this.setProfileSiteRules(this.getProfileSiteRules());
- // Adjust the profileIndex if the last profile on the list has been deleted:
- if(this.getProfileIndex()+1 > this.fieldRules.length) {
- var newIndex = this.fieldRules.length>0 ? this.fieldRules.length-1 : 0;
- this.setProfileIndex(newIndex);
- }
- // Update the profiles lists:
- this.initProfilesLists();
- // Re-init the tree:
- this.initTree();
- // Re-initialize the simple interface:
- this.initSimpleInterface();
- },
-
- createFieldRule: function(name,value,fieldRule,siteRule,overwrite,enabled) {
- var rule = new Object();
- rule['fieldRuleName'] = name;
- rule['fieldRuleValue'] = value;
- rule['fieldRuleFieldRule'] = fieldRule;
- rule['fieldRuleSiteRule'] = siteRule;
- rule['fieldRuleOverwrite'] = overwrite;
- rule['fieldRuleEnabled'] = enabled;
- return rule;
- },
-
- getRegExpPasswordLabel: function() {
- if(!arguments.callee.regExpPass) {
- arguments.callee.regExpPass = new RegExp(
- this.autofillFormsPrefs
- .getComplexValue('regExpPasswordLabel',Components.interfaces.nsIPrefLocalizedString)
- .data,
- 'i');
- }
- return arguments.callee.regExpPass;
- },
-
- initTree: function() {
- // Get the tree:
- this.tree = document.getElementById('fieldRulesTree');
-
- if(this.tree) {
-
- // Implement the TreeView interface:
- this.treeView = {
- rowCount: 0,
- setTree: function(tree){},
- getImageSrc: function(row,column) {},
- getProgressMode: function(row,column) {},
- getCellValue: function(row,column) {
- var rowObj = this.parent.getFieldRules()[row];
- if(rowObj) {
- return rowObj[column.id];
- }
- },
- getCellText: function(row,column){
- var rowObj = this.parent.getFieldRules()[row];
- if(rowObj) {
- if(column.id=='fieldRuleValue' &&
- this.parent.getRegExpPasswordLabel().test(rowObj['fieldRuleName'])) {
- // Show passwords as asterisks:
- return rowObj[column.id].replace(/./g, '*');
- } else {
- return rowObj[column.id];
- }
- }
- return '';
- },
- isEditable: function(row,column){
- // Only checkbox columns are editable:
- if(column.id=='fieldRuleOverwrite' || column.id=='fieldRuleEnabled')
- return true;
- else
- return false;
- },
- setCellValue: function(row,column,value){
- var rowObj = this.parent.getFieldRules()[row];
- if(rowObj) {
- rowObj[column.id] = value;
- // Notify the tree:
- this.parent.treeBox.invalidateRow(row);
- // Update the preferences:
- this.parent.setFieldRules();
- // Update the simple interface (add/remove enabled/disabled rules):
- if(column.id=='fieldRuleEnabled') {
- if(value == 'true') {
- this.parent.addSimpleInterfaceRow(row);
- } else {
- this.parent.removeSimpleInterfaceRow(row);
- }
- }
- }
- },
- isSeparator: function(index) {return false;},
- isSorted: function() {return false;},
- isContainer: function(index) {return false;},
- cycleHeader: function(column) {},
- getRowProperties: function(row,prop){},
- getColumnProperties: function(column,prop){},
- getCellProperties: function(row,column,prop){},
- getParentIndex: function(index) {return -1}
- };
- // Set the autofillForms object as parent:
- this.treeView.parent = this;
-
- // Set the tree length using the fieldRules list length:
- this.treeView.rowCount = this.getFieldRules().length;
-
- // Assign the treeview:
- this.tree.view = this.treeView;
-
- // The TreeSelection object:
- this.selection = this.tree.view.selection;
-
- // The TreeBox object:
- this.treeBox = this.tree.treeBoxObject;
- }
- },
-
- sortFieldRules: function(event) {
- // See method selectedFieldRule() why this has to be set to null:
- this.lastSelectedIndex = null;
-
- if(this.autofillFormsPrefs.getBoolPref('enableConfirmationDialogs')) {
- // Confirmation dialog:
- if(!this.getPrompts().confirm(
- null,
- this.getStringBundle().getString('sortFieldRulesTitle'),
- this.getStringBundle().getString('sortFieldRulesText')
- )
- ) {
- return;
- }
- }
-
- // Get the id of the column:
- var id = event.target.id;
-
- // Helper function to sort the fieldRules objects:
- function customSort(a,b) {
- // This enables comparison of boolean true and false:
- var x = a[id].toString();
- var y = b[id].toString();
-
- if(x > y) return 1;
- if(x < y) return -1;
- return 0;
- }
-
- // Sort the form field rules using the helper function:
- this.getFieldRules().sort(customSort);
-
- // Change sort direction for next click:
- if(this.ascending) {
- this.ascending = false;
- } else {
- this.getFieldRules().reverse();
- this.ascending = true;
- }
-
- // Notify the tree:
- this.treeBox.invalidate();
-
- // Clear out selections
- this.selection.select(-1);
-
- // Update the preferences:
- this.setFieldRules();
-
- // Re-initialize the simple interface:
- this.initSimpleInterface();
- },
-
- selectedFieldRule: function(event) {
- if(this.selection.currentIndex == -1) {
- // Disable buttons:
- document.getElementById('buttonRemoveFieldRule').setAttribute('disabled', 'true');
- document.getElementById('buttonMoveUpFieldRule').setAttribute('disabled', 'true');
- document.getElementById('buttonMoveDownFieldRule').setAttribute('disabled', 'true');
-
- this.lastSelectedIndex = null;
- } else if(this.selection.count == 1) {
- // The onchange event (as well as onblur, etc.) of the textboxes seems to be ignored if a new item is selected,
- // so we try and apply the field rules of the last element (if changed):
- if(this.lastSelectedIndex !== null) {
- this.applyFieldRuleOnIndex(this.lastSelectedIndex);
- }
-
- // Update the textboxes with the selected fieldRule:
- var index = this.selection.currentIndex;
- document.getElementById('fieldRuleNameTextBox').value = this.getFieldRules()[index]['fieldRuleName'];
- document.getElementById('fieldRuleValueTextBox').value = this.getFieldRules()[index]['fieldRuleValue'];
- document.getElementById('fieldRuleFieldRuleTextBox').value = this.getFieldRules()[index]['fieldRuleFieldRule'];
- document.getElementById('fieldRuleSiteRuleTextBox').value = this.getFieldRules()[index]['fieldRuleSiteRule'];
-
- // Enable/Disable buttons:
- document.getElementById('buttonRemoveFieldRule').setAttribute('disabled', 'false');
- document.getElementById('buttonMoveUpFieldRule').setAttribute(
- 'disabled',
- (index == 0)
- );
- document.getElementById('buttonMoveDownFieldRule').setAttribute(
- 'disabled',
- (index == this.getFieldRules().length-1)
- );
-
- // Save the last selected index and reset it to null for any other action than just a single selection:
- this.lastSelectedIndex = index;
- } else if(this.selection.count > 1) {
- // Enable/Disable buttons:
- document.getElementById('buttonRemoveFieldRule').setAttribute('disabled', 'false');
- document.getElementById('buttonMoveUpFieldRule').setAttribute('disabled', 'true');
- document.getElementById('buttonMoveDownFieldRule').setAttribute('disabled', 'true');
-
- this.lastSelectedIndex = null;
- }
- },
-
- initProfilesTree: function() {
- this.profilesTree = document.getElementById('profilesTree');
- if(this.profilesTree) {
-
- // Implement the profiles TreeView interface:
- this.profilesTreeView = {
- rowCount: 0,
- setTree: function(tree){},
- getImageSrc: function(row,column) {},
- getProgressMode: function(row,column) {},
- getCellValue: function(row,column) {
- if(column.id=='profilesTreeColName') {
- return this.parent.getProfileLabel(row);
- } else {
- return this.parent.getProfileSiteRule(row);
- }
- },
- getCellText: function(row,column){
- if(column.id=='profilesTreeColName') {
- return this.parent.getProfileLabel(row);
- } else {
- return this.parent.getProfileSiteRule(row);
- }
- },
- isEditable: function(row,column){return false;},
- setCellValue: function(row,column,value){},
- isSeparator: function(index) {return false;},
- isSorted: function() {return false;},
- isContainer: function(index) {return false;},
- cycleHeader: function(column) {},
- getRowProperties: function(row,prop){},
- getColumnProperties: function(column,prop){},
- getCellProperties: function(row,column,prop){},
- getParentIndex: function(index) {return -1}
- };
- // Set the autofillForms object as parent:
- this.profilesTreeView.parent = this;
-
- // Seems like we need to reset these arrays to have a consistens UI:
- this.profileLabels = null;
- this.profileSiteRules = null;
-
- // Set the tree length using the profiles labels list length:
- this.profilesTreeView.rowCount = this.getProfileLabels().length;
-
- // Assign the treeview:
- this.profilesTree.view = this.profilesTreeView;
-
- // The TreeSelection object:
- this.profilesSelection = this.profilesTree.view.selection;
-
- // The TreeBox object:
- this.profilesTreeBox = this.profilesTree.treeBoxObject;
-
- // Select the current profile:
- this.profilesSelection.select(this.getProfileIndex());
-
- // Ensure row is visible (scrolls if not):
- this.profilesTreeBox.ensureRowIsVisible(this.getProfileIndex());
- }
- },
-
- selectedProfile: function(event) {
- var index = this.profilesSelection.currentIndex;
- if(index != -1) {
- this.setProfileIndex(index);
-
- if(index > 0) {
- document.getElementById('buttonMoveUpProfile').disabled = false;
- } else {
- document.getElementById('buttonMoveUpProfile').disabled = true;
- }
- if(index+1 < this.getProfileLabels().length) {
- document.getElementById('buttonMoveDownProfile').disabled = false;
- } else {
- document.getElementById('buttonMoveDownProfile').disabled = true;
- }
-
- if(document.getElementById('profileLabelTextBox')) {
- document.getElementById('profileLabelTextBox').value = this.getProfileLabel(this.getProfileIndex());
- }
- if(document.getElementById('profileSiteRuleTextBox2')) {
- document.getElementById('profileSiteRuleTextBox2').value = this.getProfileSiteRule(this.getProfileIndex());
- }
- } else {
- document.getElementById('buttonMoveUpProfile').disabled = true;
- document.getElementById('buttonMoveDownProfile').disabled = true;
- }
- },
-
- moveUpProfile: function(event) {
- var tmpProfile = this.getFieldRules(this.getProfileIndex()-1);
- this.fieldRules[this.getProfileIndex()-1] = this.getFieldRules(this.getProfileIndex());
- this.fieldRules[this.getProfileIndex()] = tmpProfile;
- this.setFieldRules();
-
- var tmpProfileLabel = this.getProfileLabel(this.getProfileIndex()-1);
- this.getProfileLabels()[this.getProfileIndex()-1] = this.getProfileLabel(this.getProfileIndex());
- this.getProfileLabels()[this.getProfileIndex()] = tmpProfileLabel;
- this.setProfileLabels(this.getProfileLabels());
-
- var tmpProfileSiteRule = this.getProfileSiteRule(this.getProfileIndex()-1);
- this.getProfileSiteRules()[this.getProfileIndex()-1] = this.getProfileSiteRule(this.getProfileIndex());
- this.getProfileSiteRules()[this.getProfileIndex()] = tmpProfileSiteRule;
- this.setProfileSiteRules(this.getProfileSiteRules());
-
- this.setProfileIndex(this.getProfileIndex()-1);
-
- this.initProfilesLists();
- },
-
- moveDownProfile: function(event) {
- var tmpProfile = this.getFieldRules(this.getProfileIndex()+1);
- this.fieldRules[this.getProfileIndex()+1] = this.getFieldRules(this.getProfileIndex());
- this.fieldRules[this.getProfileIndex()] = tmpProfile;
- this.setFieldRules();
-
- var tmpProfileLabel = this.getProfileLabel(this.getProfileIndex()+1);
- this.getProfileLabels()[this.getProfileIndex()+1] = this.getProfileLabel(this.getProfileIndex());
- this.getProfileLabels()[this.getProfileIndex()] = tmpProfileLabel;
- this.setProfileLabels(this.getProfileLabels());
-
- var tmpProfileSiteRule = this.getProfileSiteRule(this.getProfileIndex()+1);
- this.getProfileSiteRules()[this.getProfileIndex()+1] = this.getProfileSiteRule(this.getProfileIndex());
- this.getProfileSiteRules()[this.getProfileIndex()] = tmpProfileSiteRule;
- this.setProfileSiteRules(this.getProfileSiteRules());
-
- this.setProfileIndex(this.getProfileIndex()+1);
-
- this.initProfilesLists();
- },
-
- sortProfiles: function(event) {
- var obj = new Object();
- var newSelectedIndex = this.getProfileIndex();
- var tmpProfile;
- var oldIndex;
-
- switch(event.target.id) {
- case 'profilesTreeColName':
- for(var i=0; i<this.getProfileLabels().length; i++) {
- obj[this.getProfileLabel(i)] = i;
- }
- this.getProfileLabels().sort();
- // Change sort direction for next click:
- if(this.profilesAscending) {
- this.profilesAscending = false;
- } else {
- this.getProfileLabels().reverse();
- this.profilesAscending = true;
- }
- for(var i=0; i<this.getProfileLabels().length; i++) {
- oldIndex = obj[this.getProfileLabel(i)];
- if(oldIndex == i) {
- continue;
- }
- if(oldIndex == this.getProfileIndex()) {
- newSelectedIndex = i;
- }
- tmpProfile = this.getFieldRules(i);
- this.fieldRules[i] = this.getFieldRules(oldIndex);
- this.fieldRules[oldIndex] = tmpProfile;
- }
- break;
-
- case 'profilesTreeColSiteRule':
- for(var i=0; i<this.getProfileSiteRules().length; i++) {
- obj[this.getProfileSiteRule(i)] = i;
- }
- this.getProfileSiteRules().sort();
- // Change sort direction for next click:
- if(this.profilesAscending) {
- this.profilesAscending = false;
- } else {
- this.getProfileSiteRules().reverse();
- this.profilesAscending = true;
- }
- for(var i=0; i<this.getProfileSiteRules().length; i++) {
- oldIndex = obj[this.getProfileSiteRule(i)];
- if(oldIndex == i) {
- continue;
- }
- if(oldIndex == this.getProfileIndex()) {
- newSelectedIndex = i;
- }
- tmpProfile = this.getFieldRules(i);
- this.fieldRules[i] = this.getFieldRules(oldIndex);
- this.fieldRules[oldIndex] = tmpProfile;
- }
- break;
- }
-
- this.setFieldRules();
- this.setProfileLabels(this.getProfileLabels());
- this.setProfileSiteRules(this.getProfileSiteRules());
-
- this.setProfileIndex(newSelectedIndex);
-
- this.initProfilesLists();
- },
-
- profilesTreeHandleKeyPress: function(event) {
- if(event.keyCode == 46) {
- this.removeProfile();
- }
- },
-
- invalidRegExpAlert: function(error) {
- // Invalid regular expression alert:
- this.getPrompts().alert(
- null,
- this.getStringBundle().getString('invalidRegExpTitle'),
- this.getStringBundle().getString('invalidRegExpText') + "\n\n" + error
- );
- },
-
- makeSafe: function(str) {
- // Remove all tabs and linefeeds from the given string
- // (these are used as separators):
- return str.replace(/\t|\n/g, '');
- },
-
- replaceControlCharacters: function(str) {
- return str.replace(
- /\n|\t/g,
- this.replaceControlCharactersCallback
- );
- },
-
- replaceControlCharactersCallback: function(str) {
- switch(str) {
- case "\n":
- return autofillForms.autofillFormsPrefs.getCharPref('placeholderLineBreak');
- case "\t":
- return ' ';
- default:
- return str;
- }
- },
-
- replaceControlCharacterPlaceholders: function(str) {
- try {
- var regExpObj = new RegExp(
- '('
- +this.autofillFormsPrefs.getCharPref('placeholderLineBreak')
- +')|('
- +this.autofillFormsPrefs.getCharPref('placeholderTab')
- +')',
- 'g'
- );
- return str.replace(
- regExpObj,
- this.replaceControlCharacterPlaceholdersCallback
- );
- } catch(e) {
- return str;
- }
- },
-
- replaceControlCharacterPlaceholdersCallback: function(str) {
- switch(str) {
- case autofillForms.autofillFormsPrefs.getCharPref('placeholderLineBreak'):
- return "\n";
- case autofillForms.autofillFormsPrefs.getCharPref('placeholderTab'):
- return "\t";
- default:
- return str;
- }
- },
-
- applyFieldRuleOnIndex: function(index) {
- // Check the regular expressions:
- try {
- var fieldRule = this.getRegExpStr(
- this.makeSafe(document.getElementById('fieldRuleFieldRuleTextBox').value)
- );
- document.getElementById('fieldRuleFieldRuleTextBox').value = fieldRule;
-
- var siteRule = this.getRegExpStr(
- this.makeSafe(document.getElementById('fieldRuleSiteRuleTextBox').value)
- );
- document.getElementById('fieldRuleSiteRuleTextBox').value = siteRule;
- } catch(e) {
- this.invalidRegExpAlert(e);
- return;
- }
-
- var ruleName = this.makeSafe(document.getElementById('fieldRuleNameTextBox').value);
- var ruleValue = this.makeSafe(document.getElementById('fieldRuleValueTextBox').value);
-
- if( this.getFieldRules()[index] && (
- this.getFieldRules()[index]['fieldRuleName'] != ruleName ||
- this.getFieldRules()[index]['fieldRuleValue'] != ruleValue ||
- this.getFieldRules()[index]['fieldRuleFieldRule'] != fieldRule ||
- this.getFieldRules()[index]['fieldRuleSiteRule'] != siteRule)) {
- // Update the formFieldRule on the given index:
- this.getFieldRules()[index]['fieldRuleName'] = ruleName;
- this.getFieldRules()[index]['fieldRuleValue'] = ruleValue;
- this.getFieldRules()[index]['fieldRuleFieldRule'] = fieldRule;
- this.getFieldRules()[index]['fieldRuleSiteRule'] = siteRule;
-
- // Notify the tree:
- this.treeBox.invalidateRow(index);
-
- // Update the preferences:
- this.setFieldRules();
-
- // Update the related row of the simple interface:
- this.updateSimpleInterfaceRow(index);
- }
- },
-
- applyFieldRule: function(event) {
- // Only apply changes if one item is selected:
- if(this.selection.count == 1) {
- // Update the selected formFieldRule:
- this.applyFieldRuleOnIndex(this.selection.currentIndex);
- }
- },
-
- addFieldRule: function(event) {
- // See method selectedFieldRule() why this has to be set to null:
- this.lastSelectedIndex = null;
-
- // Check the regular expressions:
- try {
- var fieldRuleFieldRuleTextBox = document.getElementById('fieldRuleFieldRuleTextBox');
- var fieldRule = this.getRegExpStr(
- this.makeSafe(fieldRuleFieldRuleTextBox.value)
- );
- fieldRuleFieldRuleTextBox.value = fieldRule;
-
- var fieldRuleSiteRuleTextBox = document.getElementById('fieldRuleSiteRuleTextBox');
- var siteRule = this.getRegExpStr(
- this.makeSafe(fieldRuleSiteRuleTextBox.value)
- );
- fieldRuleSiteRuleTextBox.value = siteRule;
- } catch(e) {
- this.invalidRegExpAlert(e);
- return;
- }
-
- var newFieldRule = this.createFieldRule(
- this.makeSafe(document.getElementById('fieldRuleNameTextBox').value),
- this.makeSafe(document.getElementById('fieldRuleValueTextBox').value),
- fieldRule,
- siteRule,
- true,
- true
- )
-
- var newFieldRuleIndex;
-
- // Add the new formFieldRule right after the selected position or to the start of the list:
- if(this.selection.currentIndex == -1 || this.selection.currentIndex == this.treeView.rowCount) {
- this.getFieldRules().unshift(newFieldRule);
- newFieldRuleIndex = 0;
- } else {
- newFieldRuleIndex = this.selection.currentIndex+1;
- this.getFieldRules().splice(
- newFieldRuleIndex,
- 0,
- newFieldRule
- );
- }
-
- // Update the tree count and notify the tree:
- this.treeView.rowCount++;
- this.treeBox.rowCountChanged(this.treeView.rowCount, +1);
- this.treeBox.invalidate();
-
- // Select the new item:
- this.selection.select(newFieldRuleIndex);
-
- // Ensure row is visible (scrolls if not):
- this.treeBox.ensureRowIsVisible(newFieldRuleIndex);
-
- // Update the preferences:
- this.setFieldRules();
-
- // Re-initialize the simple interface:
- this.initSimpleInterface();
- },
-
- removeFieldRule: function(event) {
- this.removeSelectedFieldRules();
- },
-
- moveUpFieldRule: function(event) {
- // See method selectedFieldRule() why this has to be set to null:
- this.lastSelectedIndex = null;
-
- var index = this.selection.currentIndex;
-
- // Change place with the next upper item:
- var sibling = this.getFieldRules()[index-1];
- this.getFieldRules()[index-1] = this.getFieldRules()[index];
- this.getFieldRules()[index] = sibling;
-
- // Keep moved item selected:
- this.selection.select(index-1);
-
- // Notify the tree:
- this.treeBox.invalidate();
-
- // Ensure row is visible (scrolls if not):
- this.treeBox.ensureRowIsVisible(index-1);
-
- // Update the preferences:
- this.setFieldRules();
-
- // Update the related rows of the simple interface:
- this.updateSimpleInterfaceRow(index-1);
- this.updateSimpleInterfaceRow(index);
- },
-
- moveDownFieldRule: function(event) {
- // See method selectedFieldRule() why this has to be set to null:
- this.lastSelectedIndex = null;
-
- var index = this.selection.currentIndex;
-
- // Change place with the next lower item:
- var sibling = this.getFieldRules()[index+1];
- this.getFieldRules()[index+1] = this.getFieldRules()[index];
- this.getFieldRules()[index] = sibling;
-
- // Keep moved item selected:
- this.selection.select(index+1);
-
- // Notify the tree:
- this.treeBox.invalidate();
-
- // Ensure row is visible (scrolls if not):
- this.treeBox.ensureRowIsVisible(index+1);
-
- // Update the preferences:
- this.setFieldRules();
-
- // Update the related rows of the simple interface:
- this.updateSimpleInterfaceRow(index+1);
- this.updateSimpleInterfaceRow(index);
- },
-
- removeSelectedFieldRules: function(event) {
- // See method selectedFieldRule() why this has to be set to null:
- this.lastSelectedIndex = null;
-
- if(this.autofillFormsPrefs.getBoolPref('enableConfirmationDialogs')) {
- // Confirmation dialog:
- if(!this.getPrompts().confirm(
- null,
- this.getStringBundle().getString('removeFieldRulesTitle'),
- this.getStringBundle().getString('removeFieldRulesText')
- )
- ) {
- return;
- }
- }
-
- // Start of update batch:
- this.treeBox.beginUpdateBatch();
-
- // Helper object to store a range:
- function Range(start, end) {
- this.start = start.value;
- this.end = end.value;
- }
-
- // List of ranges:
- var ranges = new Array();
-
- // Get the number of ranges:
- var numRanges = this.selection.getRangeCount();
-
- // Helper vars to store the range end points:
- var start = new Object();
- var end = new Object();
-
- // We store the list of ranges first, as calling
- // this.treeBox.rowCountChanged()
- // seems to invalidate the current selection
-
- for(var i=0; i < numRanges; i++) {
- // Get the current range end points:
- this.selection.getRangeAt(i,start,end);
- // Store them as a Range object in the ranges list:
- ranges[i] = new Range(start, end);
- }
-
- for(var i=0; i < numRanges; i++) {
- // Go through the stored ranges:
- for(var j = ranges[i].start; j <= ranges[i].end; j++) {
- // Set the selected fieldRules to null:
- this.getFieldRules()[j] = null;
- }
-
- // Calculate the new tree count:
- var count = ranges[i].end - ranges[i].start + 1;
-
- // Update the tree count and notify the tree:
- this.treeView.rowCount -= count;
- this.treeBox.rowCountChanged(ranges[i].start, -count);
- }
-
- // Collapse list by removing all the null entries
- for (var i=0; i < this.getFieldRules().length; i++) {
- if (!this.getFieldRules()[i]) {
- var j = i;
- while (j < this.getFieldRules().length && !this.getFieldRules()[j])
- j++;
- this.getFieldRules().splice(i, j-i);
- }
- }
-
- // Clear out selections
- this.selection.select(-1);
-
- // End of update batch:
- this.treeBox.endUpdateBatch();
-
- // Update the preferences:
- this.setFieldRules();
-
- // Re-initialize the simple interface:
- this.initSimpleInterface();
- },
-
- handleKeyPress: function(event) {
- if(event.keyCode == 46) {
- this.removeSelectedFieldRules();
- } else if(event.ctrlKey && event.which == 97) {
- if(this.tree && this.selection) {
- try {
- // Select all rows:
- this.selection.selectAll();
- } catch(e) {
- this.log(e);
- }
- }
- }
- },
-
- getGlobalFieldRules: function() {
- // Return the fieldRules for the selected global profile if globalProfileIndex is not out of range:
- if(this.getGlobalProfileIndex() >= 0 && this.getGlobalProfileIndex() < this.getProfileLabels().length) {
- return this.getFieldRules(this.getGlobalProfileIndex());
- } else {
- this.globalProfileIndex = 0;
- return this.getFieldRules(0);
- }
- },
-
- getFileContent: function(file) {
- var fileContent = null;
- try {
- var fis = Components.classes['@mozilla.org/network/file-input-stream;1']
- .createInstance(Components.interfaces.nsIFileInputStream);
- fis.init(file, -1, 0, 0);
- var is = Components.classes['@mozilla.org/intl/converter-input-stream;1']
- .createInstance(Components.interfaces.nsIConverterInputStream);
- is.init(fis, 'UTF-8', 1024, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
- if(is instanceof Components.interfaces.nsIUnicharLineInputStream) {
- var line = {};
- var cont;
- do {
- cont = is.readLine(line);
- if(fileContent == null) {
- fileContent = line.value;
- } else {
- fileContent += '\n'+line.value;
- }
- } while (cont);
- }
- is.close();
- fis.close();
- } catch(e) {
- this.log(e);
- }
- return fileContent;
- },
-
- setFileContent: function(file, str) {
- try {
- var fos = Components.classes['@mozilla.org/network/file-output-stream;1']
- .createInstance(Components.interfaces.nsIFileOutputStream);
- fos.init(file, 0x02 | 0x08 | 0x20, 0664, 0);
- var os = Components.classes['@mozilla.org/intl/converter-output-stream;1']
- .createInstance(Components.interfaces.nsIConverterOutputStream);
- os.init(fos, 'UTF-8', 4096, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
- os.writeString(str);
- os.close();
- fos.close();
- } catch(e) {
- this.log(e);
- }
- },
-
- getFieldRulesFile: function() {
- var file = this.getConfigDirectory();
- file.append('fieldRules.txt');
- if(!file.exists()) {
- file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0660);
- }
- return file;
- },
-
- getConfigDirectory: function() {
- var configDirectory;
- if(this.autofillFormsPrefs.prefHasUserValue('configDirectory')) {
- try {
- configDirectory = this.autofillFormsPrefs.getComplexValue(
- 'configDirectory',
- Components.interfaces.nsILocalFile
- );
- } catch(e) {
- this.autofillFormsPrefs.clearUserPref('configDirectory');
- }
- }
- if(!configDirectory) {
- configDirectory = this.getDefaultConfigDirectory();
- }
- return configDirectory;
- },
-
- getDefaultConfigDirectory: function() {
- // Use a directory "autofillForms@blueimp.net" inside Firefox profile directory as default:
- var configDirectory = Components.classes['@mozilla.org/file/directory_service;1']
- .getService(Components.interfaces.nsIProperties)
- .get('ProfD', Components.interfaces.nsILocalFile);
- configDirectory.append('autofillForms@blueimp.net');
- if(!configDirectory.exists()) {
- configDirectory.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0770);
- }
- return configDirectory;
- },
-
- setConfigDirectory: function(textBox) {
- try {
- // Create a file picker instance:
- var fp = Components.classes['@mozilla.org/filepicker;1']
- .createInstance(Components.interfaces.nsIFilePicker);
-
- // Initialize the file picker window:
- fp.init(
- window,
- this.getStringBundle().getString('selectConfigDirectory'),
- Components.interfaces.nsIFilePicker.modeGetFolder
- );
-
- // Show the file picker window:
- var rv = fp.show();
-
- if (rv == Components.interfaces.nsIFilePicker.returnOK) {
- var newDir = fp.file;
- if(newDir.path == this.getConfigDirectory().path) {
- return;
- }
- this.moveConfigFiles(newDir);
- // Save the selected directory in the preferences:
- this.autofillFormsPrefs.setComplexValue(
- 'configDirectory',
- Components.interfaces.nsILocalFile, newDir
- );
- if(textBox) {
- // Set the textbox value to the directory path:
- textBox.value = newDir.path;
- }
- }
- } catch(e) {
- this.log(e);
- }
- },
-
- resetConfigDirectory: function(textBox) {
- if(this.autofillFormsPrefs.prefHasUserValue('configDirectory')) {
- var newDir = this.getDefaultConfigDirectory();
- this.moveConfigFiles(newDir);
- this.autofillFormsPrefs.clearUserPref('configDirectory');
- if(textBox) {
- // Set the textbox value to an empty string:
- textBox.value = '';
- }
- }
- },
-
- openConfigDirectory: function() {
- var configDirectory = this.getConfigDirectory();
- if(configDirectory) {
- try {
- // Open the config directory in the operating system file manager:
- configDirectory.reveal();
- } catch(e) {
- // reveal method may not be supported on some platforms,
- // use nsIExternalProtocolService instead:
- var uri = Components.classes["@mozilla.org/network/io-service;1"]
- .getService(Components.interfaces.nsIIOService)
- .newFileURI(configDirectory);
- var protocolSvc =
- Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
- .getService(Components.interfaces.nsIExternalProtocolService);
- protocolSvc.loadUrl(uri);
- }
- }
- },
-
- moveConfigFiles: function(newDir) {
- if(this.checkConfigDirectoryOverwrite(newDir)) {
- this.moveFile(this.getFieldRulesFile(), newDir);
- this.moveFile(this.getDynamicTagsFile(), newDir);
- this.moveFile(this.getDynamicTagCodesFile(), newDir);
- this.moveFile(this.getProfileLabelsFile(), newDir);
- this.moveFile(this.getProfileSiteRulesFile(), newDir);
- return true;
- }
- return false;
- },
-
- importFromConfigDirectory: function() {
- var ok = true;
- if(this.autofillFormsPrefs.getBoolPref('enableConfirmationDialogs')) {
- ok = this.getPrompts().confirm(
- window,
- this.getStringBundle().getString('importFromConfigDirectoryTitle'),
- this.getStringBundle().getString('importFromConfigDirectoryText')
- );
- }
- if(ok) {
- this.importFieldRulesFromConfigDirectory();
- this.importDynamicTagsFromConfigDirectory();
- this.importDynamicTagCodesFromConfigDirectory();
- this.importProfileLabelsFromConfigDirectory();
- this.importProfileSiteRulesFromConfigDirectory();
- }
- },
-
- exportToConfigDirectory: function() {
- if(this.checkConfigDirectoryOverwrite(this.getConfigDirectory())) {
- this.exportFieldRulesToConfigDirectory();
- this.exportDynamicTagsToConfigDirectory();
- this.exportDynamicTagCodesToConfigDirectory();
- this.exportProfileLabelsToConfigDirectory();
- this.exportProfileSiteRulesToConfigDirectory();
- return true;
- }
- return false;
- },
-
- moveFile: function(file, newDir, newFileName) {
- try {
- // The new fileName - uses the current fileName if empty:
- newFileName = (typeof newFileName == 'string') ? newFileName : null;
-
- file.moveTo(newDir, newFileName);
- return true;
- } catch(e) {
- this.log(e);
- return false;
- }
- },
-
- checkConfigDirectoryOverwrite: function(newDir) {
- var ok = true;
- if(this.autofillFormsPrefs.getBoolPref('enableConfirmationDialogs')) {
- if(newDir.directoryEntries.hasMoreElements()) {
- ok = this.getPrompts().confirm(
- window,
- this.getStringBundle().getString('newConfigDirectoryNotEmptyTitle'),
- this.getStringBundle().getString('newConfigDirectoryNotEmptyText')
- );
- }
- }
- return ok;
- },
-
- exportFieldRulesToConfigDirectory: function() {
- var prefString;
- // Get the fieldRules string from the preferences:
- prefString = this.autofillFormsPrefs
- .getComplexValue('fieldRules',Components.interfaces.nsIPrefLocalizedString)
- .data;
- if(prefString) {
- this.setFileContent(this.getFieldRulesFile(), prefString);
- }
- },
-
- importFieldRulesFromConfigDirectory: function() {
- var prefString;
- prefString = this.getFileContent(this.getFieldRulesFile());
- if(prefString) {
- // Store the fieldRules as unicode string in the preferences:
- this.autofillFormsPrefs.setComplexValue(
- 'fieldRules',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(prefString)
- );
- }
- },
-
- getFieldRules: function(profileIndex) {
- if(this.fieldRules == null) {
- this.fieldRules = new Array();
-
- var prefString;
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- // Get the fieldRules string from the fieldRules file in the configDirectory:
- prefString = this.getFileContent(this.getFieldRulesFile());
- }
- if(!prefString) {
- // Get the fieldRules string from the preferences:
- prefString = this.autofillFormsPrefs
- .getComplexValue('fieldRules',Components.interfaces.nsIPrefLocalizedString)
- .data;
- }
-
- // On change of the "storeEncrypted" setting, we must decrypt or may not decrypt
- // the prefString in opposition to the setting - the "invertedSetting" helper var
- // helps to identify this situation:
- var boolTest = this.invertedSetting ? false : true;
-
- // If the fieldRules are stored encrypted, decrypt the prefString:
- if(this.autofillFormsPrefs.getBoolPref('storeEncrypted') == boolTest) {
- try {
- // nsISecretDecoderRing fails to handle characters above ISO-8859-1 charset
- // The usage of encodeURI/decodeURI on the fieldRule properties bypasses this problem
- prefString = this.getCryptoService().decryptString(prefString);
- } catch(e) {
- // Decrypting failed - return an empty default profile:
- this.fieldRules.push(new Array());
- this.profileIndex = 0;
- return this.fieldRules[0];
- }
- }
-
- // Get the profiles (separated by \n\n):
- var profiles = prefString.split('\n\n');
-
- for(var i=0; i<profiles.length; i++) {
- // Create an array for each profile:
- this.fieldRules.push(new Array());
-
- // Get the fieldRules rows (separated by \n):
- var rows = profiles[i].split('\n');
- if(rows[0]) {
- for(var j=0; j<rows.length; j++) {
- if(!rows[j])
- continue;
-
- // Get the fieldRules column items (separated by \t):
- var cols = rows[j].split('\t');
-
- // Create fieldRules objects and save them in the current fieldRules Array:
- if(cols.length && cols.length == 6) {
-
- // Decode the fieldRule properties:
- for(var k=0; k<cols.length; k++) {
- cols[k] = decodeURI(cols[k]);
- }
-
- this.fieldRules[i].push(
- this.createFieldRule(
- cols[0],cols[1],cols[2],cols[3],
- (cols[4] != 'false'),
- (cols[5] != 'false')
- )
- );
- }
- }
- } else
- this.fieldRules[i] = new Array();
- }
- }
-
- profileIndex = (typeof profileIndex != 'undefined') ? profileIndex : this.getProfileIndex();
-
- // Return the fieldRules for the selected profile if profileIndex is not out of range:
- if(profileIndex >= 0 && profileIndex < this.fieldRules.length)
- return this.fieldRules[profileIndex];
- else {
- this.profileIndex = 0;
- if(this.fieldRules[0] == null)
- this.fieldRules[0] = new Array();
- return this.fieldRules[0];
- }
- },
-
- setFieldRules: function() {
- if(this.fieldRules == null) {
- // Initialize the field rules:
- this.getFieldRules();
- }
-
- var profiles = '';
- var rows, cols;
- for(var i=0; i < this.fieldRules.length; i++) {
- rows = '';
- for(var j=0; j<this.fieldRules[i].length; j++) {
- cols = null;
- for(var property in this.fieldRules[i][j]) {
- if(cols == null)
- cols = '';
- else
- cols += '\t';
- // Encode the fieldRule property before adding it to the string:
- cols += encodeURI(this.fieldRules[i][j][property]);
- }
- if(j!=0)
- rows += '\n';
- rows += cols;
- }
- if(i!=0)
- profiles += '\n\n';
- profiles += rows;
- }
-
- // If the fieldRules are to be stored encrypted, encrypt the prefString:
- if(this.autofillFormsPrefs.getBoolPref('storeEncrypted')) {
- try {
- // nsISecretDecoderRing fails to handle characters above ISO-8859-1 charset
- // The usage of encodeURI/decodeURI on the fieldRule properties bypasses this problem
- profiles = this.getCryptoService().encryptString(profiles);
- } catch(e) {
- // Decrypting failed - return:
- return;
- }
- }
-
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- this.setFileContent(this.getFieldRulesFile(), profiles);
- } else {
- // Store the fieldRules objects as unicode string in the preferences:
- this.autofillFormsPrefs.setComplexValue(
- 'fieldRules',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(profiles)
- );
- }
- },
-
- copyFieldRules: function(origin) {
- var copy = new Array();
- for(var i=0; i<origin.length; i++) {
- copy.push(
- this.createFieldRule(
- origin[i]['fieldRuleName'],
- origin[i]['fieldRuleValue'],
- origin[i]['fieldRuleFieldRule'],
- origin[i]['fieldRuleSiteRule'],
- origin[i]['fieldRuleOverwrite'],
- origin[i]['fieldRuleEnabled']
- )
- )
- }
- return copy;
- },
-
- importProfile: function() {
- try {
- var file = this.filePicker('modeOpen', this.getStringBundle().getString('importProfile'));
- if(file) {
- var fis = Components.classes['@mozilla.org/network/file-input-stream;1']
- .createInstance(Components.interfaces.nsIFileInputStream);
- fis.init(file, -1, 0, 0);
-
- var is = Components.classes['@mozilla.org/intl/converter-input-stream;1']
- .createInstance(Components.interfaces.nsIConverterInputStream);
- is.init(fis, 'UTF-8', 1024, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
-
- if(this.fieldRules == null) {
- // Initialize the field rules:
- this.getFieldRules();
- }
-
- // Create a new fieldRule profile:
- var newProfileLabel = '';
- var newProfileSiteRule = '(?:)';
- var newProfileIndex = this.fieldRules.length;
- this.fieldRules.push(new Array());
-
- if (is instanceof Components.interfaces.nsIUnicharLineInputStream) {
- var line = {};
- var cont;
- do {
- cont = is.readLine(line);
-
- // Get the fieldRules column items (separated by \t) from the file:
- var cols = line.value.split('\t');
-
- if(cols.length && cols.length < 6 && cols[0] == 'autofillForms@blueimp.net') {
- // The first row has the following syntax (added SiteRule for version 0.9.1):
- // autofillForms@blueimp.net Version Label SiteRule
- if(cols.length >= 3) {
- newProfileLabel = cols[2];
- }
- if(cols.length >= 4) {
- try {
- newProfileSiteRule = this.getRegExpStr(cols[3]);
- } catch(e) {
- // Catch missing or invalid site rule
- }
- }
- } else if(cols.length && cols.length == 6) {
- // Create fieldRules objects and save them in the fieldRules Array:
- this.fieldRules[newProfileIndex].push(
- this.createFieldRule(
- cols[0],cols[1],cols[2],cols[3],
- (cols[4] != 'false'),
- (cols[5] != 'false')
- )
- );
- }
-
- } while (cont);
- }
-
- // Add profile label for default empty profile:
- if(this.getProfileLabels().length == 0) {
- this.getProfileLabels().push(this.getUniqueProfileLabel());
- }
-
- // Add the newProfileLabel to the profileLabels list (make sure it is unique):
- this.getProfileLabels().push(this.getUniqueProfileLabel(newProfileLabel));
- // Save the profileLabels list in the preferences:
- this.setProfileLabels(this.getProfileLabels());
- // Add a new profileSiteRule:
- this.getProfileSiteRules().push(newProfileSiteRule);
- // Save the profileSiteRules in the preferences:
- this.setProfileSiteRules(this.getProfileSiteRules());
- // Update the profiles lists:
- this.initProfilesLists();
-
- // Update the fieldRules:
- this.setFieldRules();
-
- is.close();
-
- fis.close();
- }
- } catch(e) {
- this.log(e);
- }
- },
-
- exportProfile: function() {
- try {
- var file = this.filePicker(
- 'modeSave',
- this.getStringBundle().getString('exportProfile'),
- this.getProfileLabel(this.getProfileIndex())+'.txt'
- );
- if(file) {
- var fos = Components.classes['@mozilla.org/network/file-output-stream;1'].
- createInstance(Components.interfaces.nsIFileOutputStream);
- fos.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
-
- var os = Components.classes['@mozilla.org/intl/converter-output-stream;1']
- .createInstance(Components.interfaces.nsIConverterOutputStream);
- os.init(fos, 'UTF-8', 4096, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
-
- var em = Components.classes['@mozilla.org/extensions/manager;1']
- .getService(Components.interfaces.nsIExtensionManager);
-
- var header = 'autofillForms@blueimp.net' + '\t'
- + em.getItemForID('autofillForms@blueimp.net').version + '\t'
- + this.getProfileLabel(this.getProfileIndex()) + '\t'
- + this.getProfileSiteRule(this.getProfileIndex()) + '\n';
- os.writeString(header);
-
- // Write the rules to file analog to storing them in the preferences:
- var cols;
- for(var i=0; i<this.getFieldRules().length; i++) {
- cols = null;
- for(var property in this.getFieldRules()[i]) {
- if(cols == null)
- cols = '';
- else
- cols += '\t';
- cols += this.getFieldRules()[i][property];
- }
- os.writeString('\n' + cols);
- }
-
- os.close();
-
- fos.close();
- }
- } catch(e) {
- this.log(e);
- }
- },
-
- filePicker: function(mode, title, fileName) {
- try {
- // Create a file picker instance:
- var fp = Components.classes['@mozilla.org/filepicker;1']
- .createInstance(Components.interfaces.nsIFilePicker);
-
- // The filename suggested to the user as a default:
- if(fileName) {
- fp.defaultString = fileName;
- }
-
- // Initialize the file picker window:
- fp.init(
- window,
- title,
- Components.interfaces.nsIFilePicker[mode]
- );
-
- // Show the file picker window:
- var rv = fp.show();
-
- if(rv==Components.interfaces.nsIFilePicker.returnOK || rv==Components.interfaces.nsIFilePicker.returnReplace)
- return fp.file;
- else
- return null;
- } catch(e) {
- return null;
- }
- },
-
- getUnicodeString: function(stringData) {
- // Create an Unicode String:
- var str = Components.classes['@mozilla.org/supports-string;1']
- .createInstance(Components.interfaces.nsISupportsString);
- // Set the String value:
- str.data = stringData;
- // Return the Unicode String:
- return str;
- },
-
- getStringBundle: function() {
- return document.getElementById('autofillFormsStringBundle');
- },
-
- getDoc: function(win) {
- if(win)
- return win.document;
- else if(content)
- return content.document;
- else
- return this.getBrowser().contentDocument;
- },
-
- getWin: function() {
- if(content)
- return content;
- else
- return this.getBrowser().contentWindow;
- },
-
- getBrowser: function() {
- try {
- return gBrowser;
- } catch(e) {
- // gBrowser is not available, so make use of the WindowMediator service instead:
- return this.getWindowMediator().getMostRecentWindow('navigator:browser').getBrowser();
- }
- },
-
- getWindowMediator: function() {
- return Components.classes['@mozilla.org/appshell/window-mediator;1']
- .getService(Components.interfaces.nsIWindowMediator);
- },
-
- getRegExpStr: function(str) {
- // Create a RegExp object using the given String:
- var regExpStr = new RegExp(str).toString();
- // Return the String representation without the surrounding slashes:
- return regExpStr.substr(1,regExpStr.length-2);
- },
-
- getPrefManager: function() {
- return Components.classes['@mozilla.org/preferences-service;1']
- .getService(Components.interfaces.nsIPrefService);
- },
-
- getCryptoService: function() {
- return Components.classes['@mozilla.org/security/sdr;1']
- .createInstance(Components.interfaces.nsISecretDecoderRing);
- },
-
- getPrompts: function() {
- return Components.classes['@mozilla.org/embedcomp/prompt-service;1']
- .getService(Components.interfaces.nsIPromptService);
- },
-
- recognizeMouseButton: function(event) {
- var modifiers = new Array();
-
- // Get the modifiers:
- if(event.altKey) modifiers.push('alt');
- if(event.ctrlKey) modifiers.push('control');
- if(event.metaKey) modifiers.push('meta');
- if(event.shiftKey) modifiers.push('shift');
-
- // Return a mouseButtonObj:
- return this.mouseButtonFactory(modifiers, 'mousebutton'+event.button);
- },
-
- mouseButtonFactory: function(modifiers, mouseButton) {
- if(typeof arguments.callee.mouseButtonObj == 'undefined') {
- arguments.callee.mouseButtonObj = function(modifiers, mouseButton) {
- this.modifiers = modifiers ? modifiers : new Array();
- this.mouseButton = mouseButton;
- this.toString = function() {
- if(this.modifiers.length) {
- return this.modifiers.join('+')+'+'+this.mouseButton;
- } else {
- return this.mouseButton;
- }
- }
- this.equals = function(mouseButtonObj) {
- if(this.mouseButton != mouseButtonObj.mouseButton) {
- return false;
- }
- if(this.modifiers.length != mouseButtonObj.modifiers.length) {
- return false;
- }
- for(var i=0; i<this.modifiers.length; i++) {
- if(this.modifiers[i] != mouseButtonObj.modifiers[i]) {
- return false;
- }
- }
- return true;
- }
- return this;
- }
- }
- return new arguments.callee.mouseButtonObj(modifiers, mouseButton);
- },
-
- getFormattedMouseButton: function(mouseButtonObj) {
- var formattedMouseButton = '';
- if(!mouseButtonObj.mouseButton) {
- return formattedMouseButton;
- }
- // Add the modifiers:
- for(var i=0; i < mouseButtonObj.modifiers.length; i++) {
- try {
- formattedMouseButton += this.getStringBundle().getString(mouseButtonObj.modifiers[i])+'+';
- } catch(e) {
- this.log(e);
- // Error in shortcut string, return empty String:
- return '';
- }
- }
- try {
- formattedMouseButton += this.getStringBundle().getString(mouseButtonObj.mouseButton);
- } catch(e) {
- // No localization for this mouse button, add generic button string :
- formattedMouseButton += this.getStringBundle().getString('mousebutton');
- // Add the index of the given mouseButton:
- formattedMouseButton += ' '+mouseButtonObj.mouseButton.substr('mousebutton'.length);
- }
- return formattedMouseButton;
- },
-
- applyMouseButton: function(event, id) {
- // Recognize the mouse button event:
- var mouseButtonObj = this.recognizeMouseButton(event);
- if(!mouseButtonObj)
- return;
- // Ignore the right mouse button (mousebutton2), as this already invokes the context menu:
- if(mouseButtonObj.mouseButton == 'mousebutton2') {
- return;
- }
- // Save the new mouse button object:
- this.setMouseButton(id, mouseButtonObj);
- // Update the mouse button textbox:
- if(event.view.document && event.view.document.getElementById(id)) {
- event.view.document.getElementById(id).value = this.getFormattedMouseButton(mouseButtonObj);
- }
- },
-
- disableMouseButton: function(event, id) {
- // Disable the mouse button:
- this.setMouseButton(id, null);
- // Update the mouse button textbox:
- if(event.view.document && event.view.document.getElementById(id)) {
- event.view.document.getElementById(id).value = '';
- }
- },
-
- getMouseButton: function(id) {
- if(this.mouseButton == null) {
- // Create a new mouseButton container object:
- this.mouseButton = new Object();
- }
- if(this.mouseButton[id] == null) {
- var mouseButtonItems = this.autofillFormsPrefs.getCharPref(id).split('+');
- var mouseButton;
- if(mouseButtonItems.length == 0) {
- mouseButton = '';
- } else {
- // Remove the last element and save it as mouseButton
- // the remaining mouseButtonItems are the modifiers:
- mouseButton = mouseButtonItems.pop();
- }
- // Create a new mouseButton object:
- this.mouseButton[id] = this.mouseButtonFactory(mouseButtonItems, mouseButton);
- }
- return this.mouseButton[id];
- },
-
- setMouseButton: function(id, mouseButtonObj) {
- var stringData;
- if(mouseButtonObj) {
- stringData = mouseButtonObj.toString();
- } else {
- stringData = '';
- }
- // Save the mouseButtonObj as Unicode String in the preferences:
- this.autofillFormsPrefs.setComplexValue(
- id,
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(stringData)
- );
- },
-
- recognizeKeys: function(event) {
- var modifiers = new Array();
- var key = '';
- var keycode = '';
-
- // Get the modifiers:
- if(event.altKey) modifiers.push('alt');
- if(event.ctrlKey) modifiers.push('control');
- if(event.metaKey) modifiers.push('meta');
- if(event.shiftKey) modifiers.push('shift');
-
- // Get the key or keycode:
- if(event.charCode) {
- key = String.fromCharCode(event.charCode).toUpperCase();
- } else {
- // Get the keycode from the keycodes list:
- keycode = this.getKeyCodes()[event.keyCode];
- if(!keycode) {
- return null;
- }
- }
-
- // Shortcut may be anything, but not 'VK_TAB' alone (without modifiers),
- // as this button is used to change focus to the 'Apply' button:
- if(modifiers.length > 0 || keycode != 'VK_TAB') {
- return this.shortcutFactory(modifiers, key, keycode);
- }
- return null;
- },
-
- shortcutFactory: function(modifiers, key, keycode) {
- if(typeof arguments.callee.shortcut == 'undefined') {
- arguments.callee.shortcut = function(modifiers, key, keycode) {
- this.modifiers = modifiers ? modifiers : new Array();
- this.key = key;
- this.keycode = keycode;
- this.toString = function() {
- if(this.modifiers.length) {
- return this.modifiers.join('+')+'+'+this.key+this.keycode;
- } else {
- return this.key+this.keycode;
- }
- }
- this.equals = function(shortcut) {
- if(this.key != shortcut.key) {
- return false;
- }
- if(this.keycode != shortcut.keycode) {
- return false;
- }
- if(this.modifiers.length != shortcut.modifiers.length) {
- return false;
- }
- for(var i=0; i<this.modifiers.length; i++) {
- if(this.modifiers[i] != shortcut.modifiers[i]) {
- return false;
- }
- }
- return true;
- }
- return this;
- }
- }
- return new arguments.callee.shortcut(modifiers, key, keycode);
- },
-
- getKeyCodes: function() {
- var keycodes = new Array();
- // Get the list of keycodes from the KeyEvent object:
- for(var property in KeyEvent) {
- keycodes[KeyEvent[property]] = property.replace('DOM_','');
- }
- // VK_BACK_SPACE (index 8) must be VK_BACK:
- keycodes[8] = 'VK_BACK';
- return keycodes;
- },
-
- applyShortcut: function(event, id) {
- // Recognize the pressed keys:
- var shortcut = this.recognizeKeys(event)
- if(!shortcut)
- return;
- // Save the new shortcut:
- this.setShortcut(id, shortcut);
- // Update the shortcut textbox:
- if(event.view.document && event.view.document.getElementById(id)) {
- event.view.document.getElementById(id).value = this.getFormattedShortcut(shortcut);
- }
- },
-
- disableShortcut: function(event, id) {
- // Disable the shortcut:
- this.setShortcut(id, null);
- // Update the shortcut textbox:
- if(event.view.document && event.view.document.getElementById(id)) {
- event.view.document.getElementById(id).value = '';
- }
- },
-
- getShortcut: function(id) {
- if(this.shortcut == null) {
- // Create a new shortcut container object:
- this.shortcut = new Object();
- }
- if(this.shortcut[id] == null) {
- var key = null;
- var keycode = null;
- var shortcutItems = this.autofillFormsPrefs
- .getComplexValue(id,Components.interfaces.nsIPrefLocalizedString)
- .data.split('+');
- if(shortcutItems.length > 0) {
- // Remove the last element and save it as key
- // the remaining shortcutItems are the modifiers:
- key = shortcutItems.pop();
- // Check if the key is a keycode:
- if(key.indexOf('VK') == 0) {
- keycode = key;
- key = null;
- }
- }
- // Create a new shortcut object:
- this.shortcut[id] = this.shortcutFactory(shortcutItems, key, keycode);
- }
- return this.shortcut[id];
- },
-
- setShortcut: function(id, shortcut) {
- var stringData;
- if(shortcut) {
- stringData = shortcut.toString();
- } else {
- stringData = '';
- }
- // Save the shortcut as Unicode String in the preferences:
- this.autofillFormsPrefs.setComplexValue(
- id,
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(stringData)
- );
- },
-
- updateShortcut: function(id) {
- if(this.shortcut == null) {
- this.shortcut = new Object();
- }
- // Setting the shortcut object to "null" will update it on the next getShortcut() call:
- this.shortcut[id] = null;
-
- // Get the keyboard shortcut elements:
- var modifiers = this.getShortcut(id).modifiers.join(' ');
- var key = this.getShortcut(id).key;
- var keycode = this.getShortcut(id).keycode;
-
- var domId = 'autofillForms' + id.replace(/shortcut/, 'Shortcut');
- var command = 'autofillForms' + id.replace(/shortcut/i, '');
-
- // Remove current key if existing:
- if(document.getElementById(domId)) {
- document.getElementById('mainKeyset').removeChild(
- document.getElementById(domId)
- );
- }
-
- // Check if keyboard shortcut is enabled:
- if(key || keycode) {
- // Create a key element:
- var keyNode = document.createElement('key');
-
- keyNode.setAttribute('id', domId);
- keyNode.setAttribute('command', command);
-
- // Set the key attributes from saved shortcut:
- keyNode.setAttribute('modifiers', modifiers);
- if(key) {
- keyNode.setAttribute('key', key);
- } else {
- keyNode.setAttribute('keycode', keycode);
- }
-
- // Add the key to the mainKeyset:
- document.getElementById('mainKeyset').appendChild(keyNode);
- }
- },
-
- getFormattedShortcut: function(shortcut) {
- var formattedShortcut = '';
- // Add the modifiers:
- for(var i=0; i < shortcut.modifiers.length; i++) {
- try {
- formattedShortcut += this.getStringBundle().getString(shortcut.modifiers[i]) + '+';
- } catch(e) {
- // Error in shortcut string, return empty String;
- return '';
- }
- }
- if(shortcut.key) {
- // Add the key:
- if(shortcut.key == ' ') {
- formattedShortcut += this.getStringBundle().getString('VK_SPACE');
- } else {
- formattedShortcut += shortcut.key;
- }
- } else if(shortcut.keycode) {
- // Add the keycode (instead of the key):
- try {
- formattedShortcut += this.getStringBundle().getString(shortcut.keycode);
- } catch(e) {
- formattedShortcut += shortcut.keycode.replace('VK_', '');
- }
- }
- return formattedShortcut;
- },
-
- replaceDynamicTags: function(fieldRuleValue) {
- // Replace all dynamic tags with the return values of their associated tag codes:
- for(var j=0; j<this.getDynamicTags().length; j++) {
- // Catch if the number of tags doesn't match the number of tag codes or if the tag code is invalid:
- try {
- var regExpObj = new RegExp(this.getDynamicTags()[j],'g');
- // We use eval() here without restrictions - the given tagCode must be trusted:
- fieldRuleValue = fieldRuleValue.replace(regExpObj, eval(this.getDynamicTagCodes()[j]));
- } catch(e) {
- this.log(e);
- }
- }
- return fieldRuleValue;
- },
-
- getDynamicTagsFile: function() {
- var file = this.getConfigDirectory();
- file.append('dynamicTags.txt');
- if(!file.exists()) {
- file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0660);
- }
- return file;
- },
-
- exportDynamicTagsToConfigDirectory: function() {
- var prefString;
- // Get the dynamicTags string from the preferences:
- prefString = this.autofillFormsPrefs
- .getComplexValue('dynamicTags',Components.interfaces.nsIPrefLocalizedString)
- .data;
- if(prefString) {
- this.setFileContent(this.getDynamicTagsFile(), prefString);
- }
- },
-
- importDynamicTagsFromConfigDirectory: function() {
- var prefString;
- prefString = this.getFileContent(this.getDynamicTagsFile());
- if(prefString) {
- // Store the dynamicTags as unicode string in the preferences:
- this.autofillFormsPrefs.setComplexValue(
- 'dynamicTags',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(prefString)
- );
- }
- },
-
- getDynamicTags: function() {
- if(this.dynamicTags == null) {
- var prefString;
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- // Get the dynamicTags string from the dynamicTags file in the configDirectory:
- prefString = this.getFileContent(this.getDynamicTagsFile());
- }
- if(!prefString) {
- prefString = this.autofillFormsPrefs
- .getComplexValue('dynamicTags',Components.interfaces.nsIPrefLocalizedString)
- .data;
- }
- this.dynamicTags = prefString.split('\t');
- }
- return this.dynamicTags;
- },
-
- setDynamicTags: function(dynamicTags) {
- // Save the dynamic tags separated by tabs:
- var prefString = dynamicTags.join('\t');
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- this.setFileContent(this.getDynamicTagsFile(), prefString);
- } else {
- this.autofillFormsPrefs.setComplexValue(
- 'dynamicTags',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(prefString)
- );
- }
- },
-
- getDynamicTagCodesFile: function() {
- var file = this.getConfigDirectory();
- file.append('dynamicTagCodes.txt');
- if(!file.exists()) {
- file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0660);
- }
- return file;
- },
-
- exportDynamicTagCodesToConfigDirectory: function() {
- var prefString;
- // Get the dynamicTagCodes string from the preferences:
- prefString = this.autofillFormsPrefs
- .getComplexValue('dynamicTagCodes',Components.interfaces.nsIPrefLocalizedString)
- .data;
- if(prefString) {
- this.setFileContent(this.getDynamicTagCodesFile(), prefString);
- }
- },
-
- importDynamicTagCodesFromConfigDirectory: function() {
- var prefString;
- prefString = this.getFileContent(this.getDynamicTagCodesFile());
- if(prefString) {
- // Store the dynamicTagCodes as unicode string in the preferences:
- this.autofillFormsPrefs.setComplexValue(
- 'dynamicTagCodes',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(prefString)
- );
- }
- },
-
- getDynamicTagCodes: function() {
- if(this.dynamicTagCodes == null) {
- var prefString;
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- // Get the dynamicTagCodes string from the dynamicTagCodes file in the configDirectory:
- prefString = this.getFileContent(this.getDynamicTagCodesFile());
- }
- if(!prefString) {
- prefString = this.autofillFormsPrefs
- .getComplexValue('dynamicTagCodes',Components.interfaces.nsIPrefLocalizedString)
- .data;
- }
- this.dynamicTagCodes = prefString.split('\t');
- }
- return this.dynamicTagCodes;
- },
-
- setDynamicTagCodes: function(dynamicTagCodes) {
- // Save the dynamic tag codes separated by tabs:
- var prefString = dynamicTagCodes.join('\t');
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- this.setFileContent(this.getDynamicTagCodesFile(), prefString);
- } else {
- this.autofillFormsPrefs.setComplexValue(
- 'dynamicTagCodes',
- Components.interfaces.nsISupportsString,
- this.getUnicodeString(prefString)
- );
- }
- },
-
- optionsInitialize: function() {
- // Save the reference to the Autofill Forms preferences branch:
- this.autofillFormsPrefs = this.getPrefManager().getBranch('extensions.autofillForms@blueimp.net.');
-
- // Initialize the profile lists:
- this.initProfilesLists();
- // Initialize the fieldRules tree:
- this.initTree();
- // Initialize the simple interface:
- this.initSimpleInterface();
-
- // Sort is to be ascending if clicked first:
- this.ascending = true;
- this.profilesAscending = true;
-
- var configDirectoryTextbox = document.getElementById('configDirectoryTextBox');
- if(configDirectoryTextbox && this.autofillFormsPrefs.prefHasUserValue('configDirectory')) {
- configDirectory = this.getConfigDirectory();
- if(configDirectory) {
- configDirectoryTextbox.value = configDirectory.path;
- }
- }
-
- // Initialize the keyboard shortcut objects:
- this.shortcut = new Object();
- this.shortcut['shortcut'] = null;
- this.shortcut['shortcutSubmit'] = null;
- this.shortcut['shortcutAllTabs'] = null;
- this.shortcut['shortcutFromProfileSelection'] = null;
- this.shortcut['shortcutProfile'] = null;
- this.shortcut['shortcutSettings'] = null;
- this.shortcut['shortcutDisplayFormDetails'] = null;
-
- // Display the shortcut combinations:
- for(var property in this.shortcut) {
- if(document.getElementById(property)) {
- document.getElementById(property).value = this.getFormattedShortcut(this.getShortcut(property));
- }
- }
-
- // Initialize the mouse button objects:
- this.mouseButton = new Object();
- this.mouseButton['mouseShortcut'] = null;
- this.mouseButton['mouseShortcutSubmit'] = null;
- this.mouseButton['mouseShortcutAllTabs'] = null;
- this.mouseButton['mouseShortcutFromProfileSelection'] = null;
- this.mouseButton['mouseShortcutProfile'] = null;
- this.mouseButton['mouseShortcutSettings'] = null;
- this.mouseButton['mouseShortcutDisplayFormDetails'] = null;
-
- // Display the mouse button combinations:
- for(var property in this.mouseButton) {
- if(document.getElementById(property)) {
- document.getElementById(property).value = this.getFormattedMouseButton(this.getMouseButton(property));
- }
- }
-
- // Parse the window params (e.g. initializing the target form field values):
- this.parseOptionsWindowParams();
- },
-
- initSimpleInterface: function() {
- var rows = document.getElementById('simpleInterfaceRows');
- if(rows) {
- while(rows.hasChildNodes()) {
- rows.removeChild(rows.firstChild);
- }
- for(var i=0; i<this.getFieldRules().length; i++) {
- // Only show enabled fieldRules:
- if(!this.getFieldRules()[i]['fieldRuleEnabled']) {
- continue;
- }
- rows.appendChild(
- this.getSimpleInterfaceRow(
- i,
- this.getFieldRules()[i]['fieldRuleName'],
- this.getFieldRules()[i]['fieldRuleValue']
- )
- );
- }
- }
- },
-
- addSimpleInterfaceRow: function(index) {
- var row = this.getSimpleInterfaceRow(
- index,
- this.getFieldRules()[index]['fieldRuleName'],
- this.getFieldRules()[index]['fieldRuleValue']
- )
- var rows = document.getElementById('simpleInterfaceRows');
- if(rows) {
- var nextSibling;
- if(rows.childNodes) {
- for(var i=index+1; i<rows.childNodes.length; i++) {
- nextSibling = document.getElementById('simpleInterfaceRow_'+i);
- if(nextSibling) {
- rows.insertBefore(row, nextSibling);
- break;
- }
- }
- }
- if(!nextSibling) {
- rows.appendChild(row);
- }
- }
- },
-
- removeSimpleInterfaceRow: function(index) {
- var row = document.getElementById('simpleInterfaceRow_'+index);
- if(row) {
- row.parentNode.removeChild(row);
- }
- },
-
- getSimpleInterfaceRow: function(index, name, value) {
- if(!arguments.callee.row) {
- arguments.callee.row = document.createElement('row');
- arguments.callee.row.setAttribute('align', 'center');
- var label = document.createElement('label');
- var textbox = document.createElement('textbox');
- textbox.setAttribute(
- 'onchange',
- 'autofillForms.applySimpleInterfaceValue(this)'
- );
- textbox.setAttribute(
- 'oninput',
- 'this.value=autofillForms.replaceControlCharacters(this.value)'
- );
- textbox.setAttribute('newlines', 'pasteintact');
- arguments.callee.row.appendChild(label);
- arguments.callee.row.appendChild(textbox);
- }
- var row = arguments.callee.row.cloneNode(true);
- row.setAttribute('id', 'simpleInterfaceRow_'+index);
- row.firstChild.setAttribute('value', name+':');
- row.firstChild.setAttribute('id', 'simpleInterfaceLabel_'+index);
- row.firstChild.setAttribute('control', 'simpleInterfaceTextbox_'+index);
- row.lastChild.setAttribute('id', 'simpleInterfaceTextbox_'+index);
- row.lastChild.setAttribute('value', value);
- // Is textbox a password field?
- if(this.getRegExpPasswordLabel().test(name)) {
- row.lastChild.setAttribute('type', 'password');
- }
- return row;
- },
-
- applySimpleInterfaceValue: function(textBox) {
- // See method selectedFieldRule() why this has to be set to null:
- this.lastSelectedIndex = null;
-
- var index = parseInt(textBox.getAttribute('id').split('_')[1]);
- this.getFieldRules()[index]['fieldRuleValue'] = this.makeSafe(textBox.value);
-
- // Notify the tree (of the advanced interface):
- try {
- this.treeBox.invalidateRow(index);
- } catch(e) {
- }
-
- // Update the preferences:
- this.setFieldRules();
- },
-
- updateSimpleInterfaceRow: function(index) {
- var row = document.getElementById('simpleInterfaceRow_'+index);
- if(row) {
- row.firstChild.value = this.getFieldRules()[index]['fieldRuleName']+':';
- row.lastChild.value = this.getFieldRules()[index]['fieldRuleValue'];
- // Is textbox a password field?
- if(this.getRegExpPasswordLabel().test(this.getFieldRules()[index]['fieldRuleName'])) {
- row.lastChild.setAttribute('type', 'password');
- } else {
- row.lastChild.removeAttribute('type');
- }
- }
- },
-
- getFieldRuleNameForElement: function(element) {
- // Use the form field label as name if available:
- var labelValue = this.getLabelForElement(element);
- // Remove the colon, if present:
- if(labelValue && labelValue.charAt(labelValue.length-1) == ':') {
- labelValue = labelValue.substr(0, labelValue.length-1);
- }
- // If no label could be found, use the name or the id with the first character in upper case:
- if(!labelValue) {
- labelValue = element.name;
- if(!labelValue) {
- labelValue = element.id;
- }
- if(labelValue) {
- labelValue = labelValue.charAt(0).toUpperCase() + labelValue.substr(1);
- }
- }
- return labelValue;
- },
-
- getRegExpStrForValue: function(value) {
- try {
- // Remove unsave characters, escape regexp characters and return the regexp string:
- return this.getRegExpStr('(?:^'+this.escapeRegExp(this.makeSafe(value))+'$)');
- } catch(e) {
- // If an error occurs, return the safe value string.
- // If using it as regular expression fails a simple string comparison is used:
- return this.makeSafe(value);
- }
- },
-
- getFieldRuleForElement: function(element) {
- var name = element.name;
- // If no name is available use the label as fallback:
- if(!name) {
- name = this.getLabelForElement(element);
- }
- // If no name and no label is available use the id as fallback:
- if(!name) {
- name = element.id;
- }
- try {
- // Remove unsave characters, escape regexp characters and return the regexp string:
- return this.getRegExpStr('(?:^'+this.escapeRegExp(this.makeSafe(name))+'$)');
- } catch(e) {
- // If an error occurs, return an always matching regexp string:
- return '(?:)';
- }
- },
-
- getSiteRuleForURL: function(url) {
- try {
- // Remove unsave characters, escape regexp characters and return the regexp string:
- return this.getRegExpStr('(?:^'+this.escapeRegExp(this.makeSafe(url))+')');
- } catch(e) {
- // If an error occurs, return an always matching regexp string:
- return '(?:)';
- }
- },
-
- parseOptionsWindowParams: function() {
- // Check the windows arguments:
- if(window.arguments && window.arguments[0]) {
- if(window.arguments[0].targetFormField) {
- var formFieldObject = window.arguments[0].targetFormField;
-
- var value;
- switch(formFieldObject.type) {
- case 'checkbox':
- case 'radio':
- case 'select-one':
- case 'select-multiple':
- value = this.getRegExpStrForValue(formFieldObject.value);
- break;
- default:
- value = this.replaceControlCharacters(formFieldObject.value);
- break;
- }
-
- var location = this.getDoc().location;
-
- // Reset the targetFormField of the autofillForms object referenced by window.arguments[0]:
- window.arguments[0].targetFormField = null;
-
- // Set the textbox values using the form field properties and the current document location:
- document.getElementById('fieldRuleNameTextBox').value
- = this.getFieldRuleNameForElement(formFieldObject)
- + (location.hostname ? ' - ' + location.hostname : '');
- document.getElementById('fieldRuleValueTextBox').value = value;
- document.getElementById('fieldRuleFieldRuleTextBox').value
- = this.getFieldRuleForElement(formFieldObject);
- document.getElementById('fieldRuleSiteRuleTextBox').value
- = this.getSiteRuleForURL(location.protocol + '//' + location.host);
-
- // Make sure the main pane is selected:
- document.getElementById('autofillFormsPrefs').showPane(
- document.getElementById('autofillFormsPrefPaneMain')
- );
-
- // Set the focus to the name field:
- document.getElementById('fieldRuleNameTextBox').focus();
- } else if(window.arguments[0].newProfileFromForm) {
- // Make sure the main pane is selected:
- document.getElementById('autofillFormsPrefs').showPane(
- document.getElementById('autofillFormsPrefPaneMain')
- );
- }
- }
- },
-
- optionsFinalize: function() {
- },
-
- showProfileSwitcher: function() {
- if(this.autofillFormsPrefs.getBoolPref('useConfigDirectory')) {
- // Always retrieve the profile labels from file if useConfigDirectory is enabled:
- this.profileLabels = null;
- }
- // The nsIPromptService select() method doesn't offer to set a preselection,
- // so we switch the current profile label with the first item (which is selected by default):
- var list;
- var currentIndex = this.getProfileIndex();
- if(currentIndex != 0) {
- // Copy the profilLabels array (so we don't change the original):
- list = new Array().concat(this.getProfileLabels());
- // Switch the current profile label with the first item:
- var tmp = list[0];
- list[0] = list[currentIndex];
- list[currentIndex] = tmp;
- } else {
- // Set the list to the profilLabels reference if it is not to be changed:
- list = this.getProfileLabels();
- }
- var selected = {};
- // Show the selection prompt:
- var ok = this.getPrompts().select(
- window,
- this.getStringBundle().getString('profileSelectionWindowTitle'),
- this.getStringBundle().getString('profileSelectionPrompt'),
- list.length,
- list,
- selected
- );
- if(ok) {
- // If nothing changed, return:
- if(selected.value == 0)
- return;
- // If the currentIndex has been selected and is not 0, it is in fact the index 0:
- if(currentIndex != 0 && selected.value == currentIndex)
- selected.value = 0;
- // Set the profile index to the selected one:
- this.setProfileIndex(selected.value)
- }
- },
-
- showDialog: function(url, params) {
- var paramObject = params ? params : this;
- return window.openDialog(
- url,
- '',
- 'chrome=yes,resizable=yes,toolbar=yes,centerscreen=yes,modal=no,dependent=no,dialog=no',
- paramObject
- );
- },
-
- inArray: function(array, item) {
- var i = array.length;
- while(i--)
- if(array[i] === item)
- return true;
- return false;
- },
-
- displayFormDetails: function() {
- this.searchAndDisplayFormDetails(this.getWin());
- },
-
- searchAndDisplayFormDetails: function(win) {
- win = win ? win : this.getWin();
-
- var doc = this.getDoc(win);
-
- // Check if any web forms are available on the current window:
- if(doc && doc.forms && doc.forms.length > 0) {
-
- // Go through the forms:
- for(var i = 0; i < doc.forms.length; i++) {
-
- // The form elements list:
- var elements = doc.forms[i].elements;
-
- // Go through the form elements:
- for(var j = 0; j < elements.length; j++) {
- // Only display valid form fields:
- if(this.isValidFormField(elements[j])) {
- this.displayFormElementDetails(elements[j], j, i, doc);
- }
- }
- }
- }
-
- // Recursive call for all subframes:
- for(var f=0; f < win.frames.length; f++) {
- this.searchAndDisplayFormDetails(win.frames[f]);
- }
- },
-
- isValidFormField: function(element) {
- if(element.disabled) {
- return false;
- }
- if(!arguments.callee.regExpFormFieldType) {
- arguments.callee.regExpFormFieldType = new RegExp(
- this.autofillFormsPrefs.getCharPref('regExpFormFieldTypes')
- );
- }
- return arguments.callee.regExpFormFieldType.test(element.type);
- },
-
- displayFormElementDetails: function(element, elementNumber, formNumber, doc) {
- // Create a unique id for the form element:
- var id = 'autofillForms-f' + formNumber + '-e' + elementNumber;
-
- // Remove the form details node if already present
- // (nodeType 1 is an element node):
- if(element.nextSibling && element.nextSibling.nodeType == 1 && element.nextSibling.getAttribute('id') == id) {
- element.parentNode.removeChild(element.nextSibling);
- return;
- }
-
- // Create a "span" node with element details:
- var text;
- // Display the element name if available, else the element id if available, else an empty name:
- if(element.name || !element.id) {
- text = 'name="' + element.name;
- } else {
- text = 'id="' + element.id;
- }
- // Display the element value:
- text += '" value="' + element.value + '"';
- var span = doc.createElement('span');
- span.setAttribute('id', id);
- span.setAttribute('style', this.autofillFormsPrefs.getCharPref('formDetailsStyle'));
- span.setAttribute('title', text);
- span.appendChild(doc.createTextNode(text));
-
- // Insert the form details node after the element:
- if(element.nextSibling)
- element.parentNode.insertBefore(span, element.nextSibling);
- else
- element.parentNode.appendChild(span);
- },
-
- ruleEditorInitialize: function() {
- // Save the reference to the Autofill Forms preferences branch:
- this.autofillFormsPrefs = this.getPrefManager().getBranch('extensions.autofillForms@blueimp.net.');
-
- if(window.arguments && window.arguments[0] && window.arguments[0].attributes) {
- this.currentRuleField = window.arguments[0];
- }
-
- // Initialize the ruleElementTypes:
- this.ruleElementTypes = new Array();
- this.ruleElementTypes.push('contains');
- this.ruleElementTypes.push('beginsWith');
- this.ruleElementTypes.push('endsWith');
- this.ruleElementTypes.push('equals');
-
- // If the rule editor is used to edit the site rule, add two predefined protocol rules:
- if(this.currentRuleField && this.currentRuleField.id && this.currentRuleField.id.indexOf('SiteRule') != -1) {
- this.ruleEditorAdd('beginsWith', 'http:\/\/');
- this.ruleEditorAdd('beginsWith', 'https:\/\/');
- } else {
- this.ruleEditorAdd();
- }
- },
-
- ruleEditorSave: function() {
- if(document.getElementById('ruleElementsList')) {
- var str = '';
- var richlistbox = document.getElementById('ruleElementsList');
- var richlistitems = richlistbox.getElementsByTagName('richlistitem');
- var menulists,textboxes;
-
- // Go through the richlistbox items:
- for(var i=0; i<richlistitems.length; i++) {
- // Link the conditions as disjunctions (OR-Relations);
- if(str.length != 0)
- str += '|';
- menulists = richlistitems[i].getElementsByTagName('menulist');
- textboxes = richlistitems[i].getElementsByTagName('textbox');
-
- // Add the current condition to the string:
- switch(menulists[0].selectedItem.value) {
- case 'contains':
- str += '(?:' + textboxes[0].value + ')';
- break;
- case 'beginsWith':
- str += '(?:^' + textboxes[0].value + ')';
- break;
- case 'endsWith':
- str += '(?:' + textboxes[0].value + '$)';
- break;
- case 'equals':
- str += '(?:^' + textboxes[0].value + '$)';
- break;
- }
- }
- if(this.currentRuleField) {
- // Set the current field value to the created string:
- this.currentRuleField.value = str;
- // Call the onchange handler:
- if(this.currentRuleField.onchange) {
- this.currentRuleField.onchange();
- }
- // Call the focus handler:
- if(this.currentRuleField.focus) {
- this.currentRuleField.focus();
- }
- }
- }
- return true;
- },
-
- ruleEditorAdd: function(type, ruleElement) {
- if(document.getElementById('ruleElementsList')) {
- var richlistbox = document.getElementById('ruleElementsList');
-
- var richlistitem,menulist,menupopup,menuitem,textbox,label;
-
- richlistitem = document.createElement('richlistitem');
-
- // Create the condition type menu:
- menulist = document.createElement('menulist');
- menupopup = document.createElement('menupopup');
-
- var selectedIndex = 0;
-
- // Create the menu of ruleElementTypes:
- for(var i=0; i<this.ruleElementTypes.length; i++) {
- menuitem = document.createElement('menuitem');
- menuitem.setAttribute(
- 'value',
- this.ruleElementTypes[i]
- );
- menuitem.setAttribute(
- 'label',
- this.getStringBundle().getString(this.ruleElementTypes[i] + 'RuleType')
- );
- menupopup.appendChild(menuitem);
-
- // Set the selectedIndex:
- if(type != null && type == this.ruleElementTypes[i])
- selectedIndex = i;
- }
-
- menulist.appendChild(menupopup);
- richlistitem.appendChild(menulist);
-
- // Create the textbox:
- textbox = document.createElement('textbox');
- if(ruleElement != null)
- textbox.setAttribute('value',ruleElement);
- textbox.setAttribute('flex','1');
- richlistitem.appendChild(textbox);
-
- richlistbox.appendChild(richlistitem);
-
- // Select the menuitem:
- menulist.selectedIndex = selectedIndex;
- }
- },
-
- ruleEditorRemove: function(index) {
- var ruleElementsList = document.getElementById('ruleElementsList');
- if(ruleElementsList) {
- if(this.autofillFormsPrefs.getBoolPref('enableConfirmationDialogs')) {
- // Confirmation dialog:
- if(!this.getPrompts().confirm(
- null,
- this.getStringBundle().getString('removeRuleConditionTitle'),
- this.getStringBundle().getString('removeRuleConditionText')
- )
- ) {
- return;
- }
- }
-
- var richlistbox = ruleElementsList;
- if(index)
- richlistbox.selectedIndex = index;
- if(richlistbox.selectedItem && richlistbox.selectedIndex != -1)
- richlistbox.removeChild(richlistbox.selectedItem);
- }
- },
-
- ruleEditorIsTextBoxFocused: function() {
- return this.ruleEditorTextBoxFocused;
- },
-
- ruleEditorFocus: function() {
- var focusedElement = document.commandDispatcher.focusedElement;
-
- // Monitor if a textbox is focused:
- if(!this.ruleEditorTextBoxFocused && focusedElement && focusedElement.tagName == 'html:input') {
- this.ruleEditorTextBoxFocused = true;
- } else if(this.ruleEditorTextBoxFocused && focusedElement && focusedElement.tagName == 'richlistbox') {
- this.ruleEditorTextBoxFocused = false;
- }
- },
-
- ruleEditorHandleKeyPress: function(event) {
- // Only remove a dynamic tag on delete key press if no textbox is focused:
- if(event.keyCode == 46 && !this.ruleEditorIsTextBoxFocused()) {
- this.ruleEditorRemove();
- }
- },
-
- ruleEditorFinalize: function() {
- this.currentRuleField = null;
- },
-
- tagEditorInitialize: function() {
- // Save the reference to the Autofill Forms preferences branch:
- this.autofillFormsPrefs = this.getPrefManager().getBranch('extensions.autofillForms@blueimp.net.');
-
- // Add existing tags to the list:
- for(var i=0; i<this.getDynamicTags().length; i++) {
- // Catch if the number of tags doesn't match the number of tag codes:
- try {
- this.tagEditorAdd(this.getDynamicTags()[i],this.getDynamicTagCodes()[i])
- } catch(e) {
- this.log(e);
- }
- }
- },
-
- tagEditorSave: function() {
- var richlistbox = document.getElementById('tagList');
- if(richlistbox) {
- var richlistitems = richlistbox.getElementsByTagName('richlistitem');
- var textboxes;
-
- var dynamicTags = new Array();
- var dynamicTagCodes = new Array();
-
- // Go through the richlistbox items:
- for(var i=0; i<richlistitems.length; i++) {
- textboxes = richlistitems[i].getElementsByTagName('textbox');
-
- // Add the dynamic tags and their associated tag codes to the lists:
- dynamicTags.push(this.makeSafe(textboxes[0].value));
- dynamicTagCodes.push(this.makeSafe(textboxes[1].value));
- }
-
- // Save the lists in the preferences:
- this.setDynamicTags(dynamicTags);
- this.setDynamicTagCodes(dynamicTagCodes);
- }
- return true;
- },
-
- tagEditorAdd: function(tag, tagCode) {
- var richlistbox = document.getElementById('tagList');
- if(richlistbox) {
- var richlistitem,textbox;
-
- richlistitem = document.createElement('richlistitem');
-
- // Create the tag textbox:
- textbox = document.createElement('textbox');
- textbox.setAttribute('class','tag');
- if(tag != null)
- textbox.setAttribute('value',tag);
- richlistitem.appendChild(textbox);
-
- // Create the tagCode textbox:
- textbox = document.createElement('textbox');
- textbox.setAttribute('class','tagCode');
- textbox.setAttribute('flex','1');
- if(tagCode != null)
- textbox.setAttribute('value',tagCode);
- richlistitem.appendChild(textbox);
-
- richlistbox.appendChild(richlistitem);
- }
- },
-
- tagEditorRemove: function(index) {
- var richlistbox = document.getElementById('tagList');
- if(richlistbox) {
- if(this.autofillFormsPrefs.getBoolPref('enableConfirmationDialogs')) {
- // Confirmation dialog:
- if(!this.getPrompts().confirm(
- null,
- this.getStringBundle().getString('removeDynamicTagTitle'),
- this.getStringBundle().getString('removeDynamicTagText')
- )
- ) {
- return;
- }
- }
- if(index)
- richlistbox.selectedIndex = index;
- if(richlistbox.selectedItem && richlistbox.selectedIndex != -1)
- richlistbox.removeChild(richlistbox.selectedItem);
- }
- },
-
- tagEditorValidate: function(index) {
- var richlistbox = document.getElementById('tagList');
- if(richlistbox) {
- if(index)
- richlistbox.selectedIndex = index;
- if(richlistbox.selectedItem) {
- var tagCode = richlistbox.selectedItem.lastChild.value;
- var validationResultTextBox = document.getElementById('validationResultTextBox');
- try {
- validationResultTextBox.removeAttribute('style');
- // We use eval() here without restrictions - the given tagCode must be trusted:
- validationResultTextBox.value = eval(tagCode);
- } catch(e) {
- validationResultTextBox.setAttribute('style', 'color:red;');
- validationResultTextBox.value = e;
- }
- }
- }
- },
-
- tagEditorIsTextBoxFocused: function() {
- return this.tagEditorTextBoxFocused;
- },
-
- tagEditorFocus: function() {
- var focusedElement = document.commandDispatcher.focusedElement;
-
- // Monitor if a textbox is focused:
- if(!this.tagEditorTextBoxFocused && focusedElement && focusedElement.tagName == 'html:input') {
- this.tagEditorTextBoxFocused = true;
- } else if(this.tagEditorTextBoxFocused && focusedElement && focusedElement.tagName == 'richlistbox') {
- this.tagEditorTextBoxFocused = false;
- }
- },
-
- tagEditorHandleKeyPress: function(event) {
- // Only remove a dynamic tag on delete key press if no textbox is focused:
- if(event.keyCode == 46 && !this.tagEditorIsTextBoxFocused()) {
- this.tagEditorRemove();
- }
- },
-
- tagEditorFinalize: function() {
- },
-
- openHelp: function(topic) {
- if(!topic) {
- topic = '';
- }
- var url = this.autofillFormsPrefs.getCharPref('helpURL').replace(/\[TOPIC\]$/, topic);
- this.openNewTab(url, true);
- },
-
- openNewTab: function(url, focus) {
- var helpTab = this.getBrowser().addTab(url);
- if(focus) {
- this.getBrowser().selectedTab = helpTab;
- this.getWindowMediator().getMostRecentWindow('navigator:browser').focus();
- }
- },
-
- addLeadingZeros: function(number, length) {
- number = number.toString();
- while(number.length < length) {
- number = '0'+number;
- }
- return number;
- },
-
- escapeRegExp: function(str) {
- if (!arguments.callee.regExp) {
- var specials = new Array(
- '^', '$', '*', '+', '?', '.', '|', '/',
- '(', ')', '[', ']', '{', '}', '\\'
- );
- arguments.callee.regExp = new RegExp(
- '(\\' + specials.join('|\\') + ')', 'g'
- );
- }
- return str.replace(arguments.callee.regExp, '\\$1');
- },
-
- getClipboardText: function() {
- var clipboardText = null;
- var clip = Components.classes['@mozilla.org/widget/clipboard;1']
- .getService(Components.interfaces.nsIClipboard);
- if(!clip) {
- return null;
- }
-
- var trans = Components.classes['@mozilla.org/widget/transferable;1']
- .createInstance(Components.interfaces.nsITransferable);
- if(!trans) {
- return null;
- }
-
- trans.addDataFlavor('text/unicode');
-
- clip.getData(trans, clip.kGlobalClipboard);
-
- var str = new Object();
- var strLength = new Object();
-
- trans.getTransferData('text/unicode', str, strLength);
-
- if(str) {
- str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
- }
- if(str) {
- clipboardText = str.data.substring(0, strLength.value / 2);
- }
-
- return clipboardText
- },
-
- getMasterSecurityDevice: function() {
- return Components.classes['@mozilla.org/security/pk11tokendb;1']
- .getService(Components.interfaces.nsIPK11TokenDB);
- },
-
- log: function(aMessage, aSourceName, aSourceLine, aLineNumber, aColumnNumber, aFlags, aCategory) {
- var consoleService = Components.classes['@mozilla.org/consoleservice;1']
- .getService(Components.interfaces.nsIConsoleService);
- if(aSourceName != 'undefined') {
- var scriptError = Components.classes["@mozilla.org/scripterror;1"]
- .createInstance(Components.interfaces.nsIScriptError);
- scriptError.init(
- aMessage,
- aSourceName,
- aSourceLine,
- aLineNumber,
- aColumnNumber,
- aFlags,
- aCategory
- );
- consoleService.logMessage(scriptError);
- } else {
- consoleService.logStringMessage(aMessage);
- }
- },
-
- finalizeToolbarButtonStatus: function() {
- var autofillFormsButton = document.getElementById('autofillFormsButton');
- var hideToolbarButton = this.autofillFormsPrefs.getBoolPref('hideToolbarButton');
- if(!autofillFormsButton && !hideToolbarButton) {
- // If the toolbar button icon has been removed from the toolbar by drag&drop
- // enable the hideToolbarButton setting:
- this.autofillFormsPrefs.setBoolPref('hideToolbarButton', true);
- } else if(autofillFormsButton && !autofillFormsButton.getAttribute('hidden')) {
- // If the toolbar button icon has been added to the toolbar by drag&drop
- // disable the hideToolbarButton setting:
- this.autofillFormsPrefs.setBoolPref('hideToolbarButton', false);
- }
- },
-
- finalize: function() {
- this.finalizeToolbarButtonStatus();
-
- // Remove the content area context menu listener:
- var contentAreaContextMenu = document.getElementById('contentAreaContextMenu');
- if(contentAreaContextMenu) {
- contentAreaContextMenu.removeEventListener(
- 'popupshowing',
- this.contentAreaContextMenuEventListener,
- false
- );
- }
-
- // Remove the preferences Observer:
- this.autofillFormsPrefs.removeObserver('', this);
- }
-
- }